igc.cc
lowranceusr.cc
mtk_logger.cc
- navilink.cc
osm.cc
ozi.cc
qstarz_bl_1000.cc
random.cc
- sbn.cc
- sbp.cc
shape.cc
skytraq.cc
subrip.cc
legacyformat.h
igc.h
lowranceusr.h
- navilink.h
nmea.h
osm.h
qstarz_bl_1000.h
lowranceusr
mtk
multiurlgpx
- navilink
nmea
osm
ozi
realtime
resample
route_reverse
- sbn
- sbp
serialization
shape
simplify-relative
--- /dev/null
+/*
+ NaviGPS serial protocol.
+
+ Copyright (C) 2007 Tom Hughes, tom@compton.nu
+ Copyright (C) 2008 Rodney Lorrimar, rodney@rodney.id.au
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ */
+
+
+/* Based on description at http://wiki.splitbrain.org/navilink */
+
+#include <cstdio> // for fprintf, stderr
+#include <cstring> // for memcpy, memset, strncpy
+
+#include <QByteArray> // for QByteArray
+#include <QDate> // for QDate
+#include <QDateTime> // for QDateTime
+#include <QString> // for QString, operator==
+#include <QThread> // for QThread
+#include <QTime> // for QTime
+#include <QVector> // for QVector
+#include <QtCore> // for qRound, qPrintable, UTC
+
+#include "defs.h"
+#include "navilink.h"
+#include "gbfile.h" // for gbfwrite, gbfclose, gbfopen, gbfread
+#include "gbser.h" // for gbser_read_wait, gbser_deinit, gbs...
+#include "jeeps/gpsmath.h" // for GPS_Math_WGS84_To_UTM_EN
+#include "jeeps/gpsport.h" // for int32
+#include "src/core/datetime.h" // for DateTime
+
+
+#define MYNAME "NAVILINK"
+
+static char* nuketrk = nullptr;
+static char* nukerte = nullptr;
+static char* nukewpt = nullptr;
+static char* nukedlg = nullptr;
+static char* poweroff = nullptr;
+static char* datalog = nullptr;
+
+static void* serial_handle = nullptr;
+static gbfile* file_handle = nullptr;
+
+static unsigned char* track_data;
+static unsigned char* track_data_ptr;
+static unsigned char* track_data_end;
+static unsigned track_serial;
+static Waypoint** route_waypts;
+static unsigned* route_ids;
+static unsigned route_id_ptr;
+
+static enum {
+ READING,
+ WRITING
+} operation = READING;
+
+#define SERIAL_TIMEOUT 8000
+#define CLEAR_DATALOG_TIME 7000
+
+#define MAX_WAYPOINTS 1000
+#define MAX_SUBROUTES 9
+#define MAX_SUBROUTE_LENGTH 14
+#define MAX_ROUTE_LENGTH (MAX_SUBROUTES * MAX_SUBROUTE_LENGTH - 1)
+#define MAX_READ_TRACKPOINTS 512
+#define MAX_WRITE_TRACKPOINTS 127
+#define MAX_READ_LOGPOINTS 256
+
+#define PID_SYNC 0xd6
+#define PID_ACK 0x0c
+#define PID_NAK 0x00
+#define PID_QRY_INFORMATION 0x20
+#define PID_QRY_FW_VERSION 0xfe
+#define PID_DATA 0x03
+#define PID_ADD_A_WAYPOINT 0x3c
+#define PID_QRY_WAYPOINTS 0x28
+#define PID_QRY_ROUTE 0x24
+#define PID_DEL_WAYPOINT 0x36
+#define PID_DEL_ALL_WAYPOINT 0x37
+#define PID_DEL_ROUTE 0x34
+#define PID_DEL_ALL_ROUTE 0x35
+#define PID_ADD_A_ROUTE 0x3d
+#define PID_ERASE_TRACK 0x11
+#define PID_READ_TRACKPOINTS 0x14
+#define PID_WRITE_TRACKPOINTS 0x16
+#define PID_CMD_OK 0xf3
+#define PID_CMD_FAIL 0xf4
+#define PID_QUIT 0xf2
+#define PID_INFO_DATALOG 0x1c
+#define PID_READ_DATALOG 0x14
+#define PID_CLEAR_DATALOG 0x1b
+
+static
+const char* const icon_table[] = {
+ "Star",
+ "Flag",
+ "House",
+ "Left Sign",
+ "Telegraph Pole",
+ "People",
+ "Fuel",
+ "Phone",
+ "Pole",
+ "Mountain",
+ "Water",
+ "Tree",
+ "Road Narrows",
+ "Crossroads",
+ "Road Fork",
+ "Turn Right",
+ "Turn Left",
+ "Bird",
+ "3D House",
+ "Trig Point",
+ "Tower",
+ "Cable Car",
+ "Church",
+ "Telegraph Pole",
+ "Skier",
+ "Anchor",
+ "Fish",
+ "Fishes",
+ "Rain",
+ "Fisherman",
+ "Tower",
+ "Boats",
+ "Boat",
+ "Bicycle",
+ "Railway Track",
+ "Dollar Sign",
+ "Bus",
+ "Camera",
+ "Fuel Pump",
+ "Cup",
+ "Merging Road",
+ "Plane",
+ "Red Cross",
+ "House",
+ "Parking"
+};
+
+static
+QVector<arglist_t> navilink_args = {
+ {
+ "nuketrk", &nuketrk, "Delete all track points", nullptr, ARGTYPE_BOOL,
+ ARG_NOMINMAX, nullptr
+ },
+ {
+ "nukerte", &nukerte, "Delete all routes", nullptr, ARGTYPE_BOOL,
+ ARG_NOMINMAX, nullptr
+ },
+ {
+ "nukewpt", &nukewpt, "Delete all waypoints", nullptr, ARGTYPE_BOOL,
+ ARG_NOMINMAX, nullptr
+ },
+ {
+ "nukedlg", &nukedlg, "Clear the datalog", nullptr, ARGTYPE_BOOL,
+ ARG_NOMINMAX, nullptr
+ },
+ {
+ "datalog", &datalog, "Read from datalogger buffer",
+ nullptr, ARGTYPE_BOOL, ARG_NOMINMAX, nullptr
+ },
+ {
+ "power_off", &poweroff, "Command unit to power itself down",
+ nullptr, ARGTYPE_BOOL, ARG_NOMINMAX, nullptr
+ },
+};
+
+static void (*write_waypoint)(const Waypoint*) = nullptr;
+static void (*write_track_start)(const route_head* track) = nullptr;
+static void (*write_track_point)(const Waypoint* waypt) = nullptr;
+static void (*write_track_end)(const route_head* track) = nullptr;
+static void (*write_route_start)(const route_head* track) = nullptr;
+static void (*write_route_point)(const Waypoint* waypt) = nullptr;
+static void (*write_route_end)(const route_head* track) = nullptr;
+
+static int
+find_icon_from_descr(const QString& descr)
+{
+ for (unsigned int i = 0; i < sizeof(icon_table) / sizeof(const char*); i++) {
+ if (0 == descr.compare(icon_table[i])) {
+ return i;
+ }
+ }
+
+ return 0;
+}
+
+static void
+free_waypoints(Waypoint** waypts)
+{
+ for (Waypoint** wayptp = waypts; wayptp < waypts + MAX_WAYPOINTS; wayptp++) {
+ if (*wayptp) {
+ delete *wayptp;
+ }
+ }
+
+ xfree(waypts);
+}
+
+static unsigned
+compare_waypoints(const Waypoint* waypt1, const Waypoint* waypt2)
+{
+ return waypt1->latitude == waypt2->latitude &&
+ waypt1->longitude == waypt2->longitude &&
+ waypt1->altitude == waypt2->altitude &&
+ waypt1->shortname == waypt2->shortname;
+}
+
+unsigned
+navilink_checksum_packet(const unsigned char* packet, unsigned length)
+{
+ unsigned checksum = 0;
+
+ while (length-- > 0) {
+ checksum += *packet++;
+ }
+
+ return checksum & 0x7fff;
+}
+
+static void
+dump_packet(const char* prefix, unsigned char* packet, unsigned length)
+{
+ unsigned i;
+
+ for (i = 0; i < length; i++) {
+ if ((i % 16) == 0) {
+ fprintf(stderr, "%s %08x :", prefix, i);
+ }
+ fprintf(stderr, " %02x", packet[i]);
+ if ((i % 16) == 15 || i == length - 1) {
+ fprintf(stderr, "\n");
+ }
+ }
+
+ fprintf(stderr, "\n");
+}
+
+static void
+write_packet(unsigned type, const void* payload, unsigned length)
+{
+ auto* packet = (unsigned char*) xmalloc(length + 9);
+
+ packet[0] = 0xa0;
+ packet[1] = 0xa2;
+ le_write16(packet + 2, length + 1);
+ packet[4] = type;
+ if (length > 0) {
+ memcpy(packet + 5, payload, length);
+ }
+ le_write16(packet + length + 5, navilink_checksum_packet(packet + 4, length + 1));
+ packet[length + 7] = 0xb0;
+ packet[length + 8] = 0xb3;
+
+ if (global_opts.debug_level >= 2) {
+ dump_packet(">>>", packet + 4, length + 1);
+ }
+
+ if (gbser_write(serial_handle, packet, length + 9) != gbser_OK) {
+ fatal(MYNAME ": Write error\n");
+ }
+
+ xfree(packet);
+}
+
+static unsigned
+read_word()
+{
+ unsigned char buffer[2];
+
+ if (gbser_read_wait(serial_handle, buffer, 2, SERIAL_TIMEOUT) != 2) {
+ fatal(MYNAME ": Read error\n");
+ }
+
+ return (buffer[1] << 8) | buffer[0];
+}
+
+/*
+ * Read a protocol packet into payload.
+ *
+ * handle_nak determines behaviour when a PID_NAK packet is read from
+ * the device:
+ * - if handle_nak is false, a fatal error will be raised.
+ * - if handle_nak is true, read_packet will simply return false.
+ *
+ * Returns true if the packet was successfully read into payload.
+ */
+static bool
+read_packet(unsigned type, void* payload,
+ int minlength, int maxlength,
+ bool handle_nak)
+{
+ if (read_word() != 0xa2a0) {
+ fatal(MYNAME ": Protocol error: Bad packet header."
+ " Is your NaviGPS in NAVILINK mode?\n");
+ }
+
+ int size;
+ if ((size = read_word()) <= minlength) {
+ fatal(MYNAME ": Protocol error: Packet too short\n");
+ }
+
+ auto* data = (unsigned char*) xmalloc(size);
+
+ if (gbser_read_wait(serial_handle, data, size, SERIAL_TIMEOUT) != size) {
+ fatal(MYNAME ": Read error reading %d byte payload\n", size);
+ }
+
+ if (global_opts.debug_level >= 2) {
+ dump_packet("<<<", data, size);
+ }
+
+ if (data[0] != type) {
+ if (handle_nak && data[0] == PID_NAK) {
+ return false;
+ }
+
+ fatal(MYNAME ": Protocol error: Bad packet type (expected 0x%02x but got 0x%02x)\n", type, data[0]);
+ }
+
+ unsigned checksum;
+ if ((checksum = read_word()) != navilink_checksum_packet(data, size)) {
+ fatal(MYNAME ": Checksum error - expected %x got %x\n",
+ navilink_checksum_packet(data, size), checksum);
+ }
+
+ if (read_word() != 0xb3b0) {
+ fatal(MYNAME ": Protocol error: Bad packet trailer\n");
+ }
+
+ if (size - 1 > maxlength) {
+ memcpy(payload, data + 1, maxlength);
+ } else {
+ memcpy(payload, data + 1, size - 1);
+ }
+
+ xfree(data);
+
+ return true;
+}
+
+static QDateTime
+decode_datetime(const unsigned char* buffer)
+{
+ QTime tm(buffer[3], buffer[4], buffer[5]);
+ QDate dt(2000 + buffer[0], buffer[1], buffer[2]);
+ return QDateTime(dt, tm, Qt::UTC);
+}
+
+static void
+encode_datetime(const QDateTime& datetime, unsigned char* buffer)
+{
+ if (datetime.isValid()) {
+ QDateTime dt = datetime.toUTC();
+ QDate date = dt.date();
+ QTime time = dt.time();
+ buffer[0] = date.year() - 2000;
+ buffer[1] = date.month();
+ buffer[2] = date.day();
+ buffer[3] = time.hour();
+ buffer[4] = time.minute();
+ buffer[5] = time.second();
+ } else {
+ memset(buffer, 0, 6);
+ }
+}
+
+static void
+decode_position(const unsigned char* buffer, Waypoint* waypt)
+{
+ waypt->latitude = le_read32(buffer + 0) / 10000000.0;
+ waypt->longitude = le_read32(buffer + 4) / 10000000.0;
+ waypt->altitude = FEET_TO_METERS(le_read16(buffer + 8));
+}
+
+static void
+encode_position(const Waypoint* waypt, unsigned char* buffer)
+{
+ le_write32(buffer + 0, qRound(waypt->latitude * 10000000));
+ le_write32(buffer + 4, qRound(waypt->longitude * 10000000));
+ le_write16(buffer + 8, qRound(METERS_TO_FEET(waypt->altitude)));
+}
+
+static unsigned
+decode_waypoint_id(const unsigned char* buffer)
+{
+ unsigned id = le_read16(buffer + 2);
+
+ if (id >= MAX_WAYPOINTS) {
+ fatal(MYNAME ": Invalid waypoint ID\n");
+ }
+
+ return id;
+}
+
+static Waypoint*
+decode_waypoint(const unsigned char* buffer)
+{
+ auto* waypt = new Waypoint;
+
+ decode_position(buffer + 12, waypt);
+ waypt->shortname = reinterpret_cast<const char*>(buffer) + 4;
+ waypt->icon_descr = icon_table[buffer[28]];
+ waypt->SetCreationTime(decode_datetime(buffer + 22));
+
+ return waypt;
+}
+
+static void
+encode_waypoint(const Waypoint* waypt, unsigned char* buffer)
+{
+ buffer[0] = 0x00;
+ buffer[1] = 0x40;
+ le_write16(buffer + 2, 0);
+ strncpy((char*)buffer + 4, CSTRc(waypt->shortname), 6);
+ buffer[10] = 0;
+ buffer[11] = 0;
+ encode_position(waypt, buffer + 12);
+ encode_datetime(waypt->GetCreationTime(), buffer + 22);
+ buffer[28] = find_icon_from_descr(waypt->icon_descr);
+ buffer[29] = 0;
+ buffer[30] = 0x00;
+ buffer[31] = 0x7e;
+}
+
+static Waypoint*
+decode_trackpoint(const unsigned char* buffer)
+{
+ auto* waypt = new Waypoint;
+
+ decode_position(buffer + 12, waypt);
+ waypt->SetCreationTime(decode_datetime(buffer + 22));
+ waypt->set_course(le_read16(buffer + 2));
+ waypt->set_speed(KPH_TO_MPS(buffer[29] * 2));
+
+ return waypt;
+}
+
+static void
+encode_trackpoint(const Waypoint* waypt, unsigned serial, unsigned char* buffer)
+{
+ double x;
+ double y;
+ int32 z;
+ char zc;
+
+ GPS_Math_WGS84_To_UTM_EN(waypt->latitude, waypt->longitude, &x, &y, &z, &zc);
+
+ le_write16(buffer + 0, serial);
+ le_write16(buffer + 2, qRound(waypt->course_value_or(0)));
+ le_write32(buffer + 4, qRound(x));
+ le_write32(buffer + 8, qRound(y));
+ encode_position(waypt, buffer + 12);
+ encode_datetime(waypt->GetCreationTime(), buffer + 22);
+ buffer[28] = z;
+ buffer[29] = qRound(MPS_TO_KPH(waypt->speed_value_or(0) / 2));
+ buffer[30] = 0x5a;
+ buffer[31] = 0x7e;
+}
+
+static Waypoint**
+serial_read_waypoints()
+{
+ Waypoint** waypts = nullptr;
+ unsigned char information[32];
+
+ if (global_opts.masked_objective & RTEDATAMASK) {
+ waypts = (Waypoint**) xcalloc(MAX_WAYPOINTS, sizeof(Waypoint*));
+ }
+
+ write_packet(PID_QRY_INFORMATION, nullptr, 0);
+ read_packet(PID_DATA, information,
+ sizeof(information), sizeof(information),
+ false);
+
+ unsigned short total = le_read16(information + 0);
+
+ for (unsigned short start = 0; start < total; start += 32) {
+ unsigned short count = total - start;
+ unsigned char payload[7];
+
+ if (count > 32) {
+ count = 32;
+ }
+
+ le_write32(payload + 0, start);
+ le_write16(payload + 4, count);
+ payload[6] = 1;
+
+ write_packet(PID_QRY_WAYPOINTS, payload, sizeof(payload));
+
+ auto* waypoints = (unsigned char*) xmalloc(count * 32);
+
+ read_packet(PID_DATA, waypoints, count * 32, count * 32, false);
+
+ for (unsigned char* w = waypoints; w < waypoints + count * 32; w = w + 32) {
+ if (global_opts.masked_objective & WPTDATAMASK) {
+ waypt_add(decode_waypoint(w));
+ }
+ if (global_opts.masked_objective & RTEDATAMASK) {
+ waypts[decode_waypoint_id(w)] = decode_waypoint(w);
+ }
+ }
+
+ xfree(waypoints);
+
+ if (global_opts.verbose_status) {
+ waypt_status_disp(total, start + count);
+ }
+ }
+
+ return waypts;
+}
+
+static unsigned int
+serial_write_waypoint_packet(const Waypoint* waypt)
+{
+ unsigned char data[32];
+ unsigned char id[2];
+
+ encode_waypoint(waypt, data);
+ write_packet(PID_ADD_A_WAYPOINT, data, sizeof(data));
+ if (!read_packet(PID_DATA, id, sizeof(id), sizeof(id), true)) {
+ fatal(MYNAME ": Could not write waypoint.\n");
+ }
+
+ return le_read16(id);
+}
+
+static void
+serial_write_waypoint(const Waypoint* waypt)
+{
+ serial_write_waypoint_packet(waypt);
+}
+
+static void
+serial_read_track()
+{
+ unsigned char information[32];
+
+ write_packet(PID_QRY_INFORMATION, nullptr, 0);
+ read_packet(PID_DATA, information,
+ sizeof(information), sizeof(information),
+ false);
+
+ unsigned int address = le_read32(information + 4);
+ unsigned short total = le_read16(information + 12);
+
+ auto* track = new route_head;
+ track_add_head(track);
+
+ while (total > 0) {
+ unsigned short count = total < MAX_READ_TRACKPOINTS ? total : MAX_READ_TRACKPOINTS;
+ unsigned char payload[7];
+
+ le_write32(payload + 0, address);
+ le_write16(payload + 4, count * 32);
+ payload[6] = 0x00;
+
+ write_packet(PID_READ_TRACKPOINTS, payload, sizeof(payload));
+
+ auto* trackpoints = (unsigned char*) xmalloc(count * 32);
+
+ read_packet(PID_DATA, trackpoints, count * 32, count * 32, false);
+ write_packet(PID_ACK, nullptr, 0);
+
+ for (unsigned char* t = trackpoints; t < trackpoints + count * 32; t = t + 32) {
+ track_add_wpt(track, decode_trackpoint(t));
+ }
+
+ xfree(trackpoints);
+
+ address = address + count * 32;
+ total = total - count;
+ }
+}
+
+static void
+serial_write_track()
+{
+ unsigned char information[32];
+ unsigned char data[7];
+
+ write_packet(PID_QRY_INFORMATION, nullptr, 0);
+ read_packet(PID_DATA, information,
+ sizeof(information), sizeof(information),
+ false);
+
+ unsigned int address = le_read32(information + 4);
+ unsigned short total = le_read16(information + 12);
+
+ le_write32(data + 0, address + total * 32);
+ le_write16(data + 4, track_data_ptr - track_data);
+ data[6] = 0x00;
+
+ write_packet(PID_WRITE_TRACKPOINTS, data, sizeof(data));
+ QThread::usleep(10000);
+ write_packet(PID_DATA, track_data, track_data_ptr - track_data);
+ read_packet(PID_CMD_OK, nullptr, 0, 0, false);
+
+ track_data_ptr = track_data;
+}
+
+static void
+serial_write_track_start(const route_head*)
+{
+ track_data = (unsigned char*) xmalloc(MAX_WRITE_TRACKPOINTS * 32);
+ track_data_ptr = track_data;
+ track_data_end = track_data + MAX_WRITE_TRACKPOINTS * 32;
+}
+
+static void
+serial_write_track_point(const Waypoint* waypt)
+{
+ if (track_data_ptr >= track_data_end) {
+ serial_write_track();
+ }
+
+ encode_trackpoint(waypt, 0, track_data_ptr);
+
+ track_data_ptr += 32;
+}
+
+static void
+serial_write_track_end(const route_head*)
+{
+ if (track_data_ptr > track_data) {
+ serial_write_track();
+ }
+
+ xfree(track_data);
+}
+
+static void
+serial_read_routes(Waypoint** waypts)
+{
+ unsigned char information[32];
+
+ write_packet(PID_QRY_INFORMATION, nullptr, 0);
+ read_packet(PID_DATA, information,
+ sizeof(information), sizeof(information),
+ false);
+
+ unsigned char routec = information[2];
+
+ for (unsigned char r = 0; r < routec; r++) {
+ unsigned char payload[7];
+ unsigned char routedata[320];
+
+ le_write32(payload + 0, r);
+ le_write16(payload + 2, 0);
+ payload[6] = 0x01;
+
+ write_packet(PID_QRY_ROUTE, payload, sizeof(payload));
+ read_packet(PID_DATA, routedata, 64, sizeof(routedata), false);
+
+ auto* route = new route_head;
+ route->rte_num = routedata[2];
+ route->rte_name = (char*)routedata + 4;
+ route_add_head(route);
+
+ for (int sr = 0; sr < MAX_SUBROUTES; sr++) {
+ for (int w = 0; w < MAX_SUBROUTE_LENGTH; w++) {
+ unsigned short id = le_read16(routedata + 34 + 32 * sr + 2 *w);
+
+ if (id == 0xffffu) {
+ w = MAX_SUBROUTE_LENGTH;
+ sr = MAX_SUBROUTES;
+ } else if (id >= MAX_WAYPOINTS) {
+ fatal(MYNAME ": Invalid waypoint ID in route\n");
+ } else if (waypts[id] == nullptr) {
+ fatal(MYNAME ": Non-existent waypoint in route\n");
+ } else {
+ route_add_wpt(route, new Waypoint(*waypts[id]));
+ }
+ }
+ }
+ }
+}
+
+static void
+serial_write_route_start(const route_head* route)
+{
+ route_ids = (unsigned int*) xmalloc(route->rte_waypt_ct() * sizeof(unsigned));
+ route_id_ptr = 0;
+}
+
+static void
+serial_write_route_point(const Waypoint* waypt)
+{
+ unsigned w;
+
+ for (w = 0; w < MAX_WAYPOINTS; w++) {
+ if (route_waypts[w] && compare_waypoints(waypt, route_waypts[w])) {
+ break;
+ }
+ }
+
+ if (w == MAX_WAYPOINTS) {
+ w = serial_write_waypoint_packet(waypt);
+ route_waypts[w] = new Waypoint(*waypt);
+ }
+
+ route_ids[route_id_ptr++] = w;
+}
+
+static void
+serial_write_route_end(const route_head* route)
+{
+ unsigned char id[1];
+
+ QString rte_name = route->rte_name;
+ if (rte_name == nullptr) {
+ rte_name = "NO NAME";
+ }
+ if (route_id_ptr > MAX_ROUTE_LENGTH) {
+ fatal(MYNAME ": Route %s too long\n", qPrintable(route->rte_name));
+ }
+
+ unsigned src = (route_id_ptr + MAX_SUBROUTE_LENGTH) / MAX_SUBROUTE_LENGTH;
+ auto* data = (unsigned char*) xmalloc(32 + src * 32);
+
+ le_write16(data + 0, 0x2000);
+ data[2] = 0;
+ data[3] = 0x20;
+ memset(data + 4, 0, 14);
+ strncpy((char*)data + 4, CSTR(rte_name), 13);
+ data[18] = 0;
+ data[19] = 0;
+ le_write32(data + 20, 0);
+ le_write32(data + 24, 0);
+ le_write16(data + 28, 0);
+ data[30] = 0x7b;
+ data[31] = 0x77;
+
+ for (unsigned sr = 0; sr < src; sr++) {
+ unsigned char* srdata = data + 32 + 32 * sr;
+ unsigned pt_offset = MAX_SUBROUTE_LENGTH * sr;
+
+ le_write16(srdata + 0, 0x2010);
+
+ for (unsigned pt = 0; pt < MAX_SUBROUTE_LENGTH; pt++) {
+ if (pt_offset + pt < route_id_ptr) {
+ le_write16(srdata + 2 + 2 * pt, route_ids[pt_offset + pt]);
+ } else {
+ le_write16(srdata + 2 + 2 * pt, 0xffffu);
+ }
+ }
+
+ srdata[30] = 0x7f;
+ srdata[31] = 0x77;
+ }
+
+ write_packet(PID_ADD_A_ROUTE, data, 32 + src * 32);
+ if (!read_packet(PID_DATA, id, sizeof(id), sizeof(id), true)) {
+ fatal(MYNAME ": Could not add route.\n");
+ }
+
+ xfree(data);
+ xfree(route_ids);
+}
+
+static int
+decode_sbp_msec(const unsigned char* buffer)
+{
+ int msec = le_read16(buffer);
+ return (msec % 1000);
+}
+
+static QDateTime
+decode_sbp_datetime_packed(const unsigned char* buffer)
+{
+ /*
+ * Packed_Date_Time_UTC:
+ * bit 31..22 :year*12+month (10 bits) : real year= year+2000
+ * bit17.21: day (5bits)
+ * bit12.16: hour (5bits)
+ * bit6..11: min (6bits)
+ * bit0..5 : sec (6bits)
+ *
+ * 0 1 2 3
+ * 01234567 01234567 01234567 01234567
+ * ........ ........ ........ ........
+ * SSSSSSMM MMMMHHHH Hdddddmm mmmmmmmm
+ */
+
+ int sec = buffer[0] & 0x3F;
+ int min = ((buffer[0] & 0xC0) >> 6) | ((buffer[1] & 0x0F) << 2);
+ int hour = ((buffer[1] & 0xF0) >> 4) | ((buffer[2] & 0x01) << 4);
+ int mday = (buffer[2] & 0x3E) >> 1;
+ int months = ((buffer[2] & 0xC0) >> 6) | buffer[3] << 2;
+ int mon = months % 12;
+ int year = 2000 + months / 12;
+
+ return {QDate(year, mon, mday), QTime(hour, min, sec), Qt::UTC};
+}
+
+static void
+decode_sbp_position(const unsigned char* buffer, Waypoint* waypt)
+{
+ waypt->latitude = le_read32(buffer + 0) / 10000000.0;
+ waypt->longitude = le_read32(buffer + 4) / 10000000.0;
+ waypt->altitude = le_read32(buffer + 8) / 100.0;
+}
+
+Waypoint*
+navilink_decode_logpoint(const unsigned char* buffer)
+{
+ auto* waypt = new Waypoint;
+
+ waypt->hdop = (buffer[0]) * 0.2f;
+ waypt->sat = buffer[1];
+ waypt->SetCreationTime(decode_sbp_datetime_packed(buffer + 4)
+ .addMSecs(decode_sbp_msec(buffer + 2)));
+ decode_sbp_position(buffer + 12, waypt);
+ waypt->set_speed(le_read16(buffer + 24) * 0.01f);
+ waypt->set_course(le_read16(buffer + 26) * 0.01f);
+
+ return waypt;
+}
+
+/*
+ * The datalog is a circular buffer, so it may be necessary to glue
+ * together two segments. This function queries the device for the
+ * circular buffer pointers, and returns two pairs of address/length.
+ * If there is only one segment (i.e. the datalog has not yet wrapped
+ * around), then seg2_addr and seg2_len will be zero.
+ */
+static void
+read_datalog_info(unsigned int* seg1_addr, unsigned int* seg1_len,
+ unsigned int* seg2_addr, unsigned int* seg2_len)
+{
+ unsigned char info[16];
+
+ write_packet(PID_INFO_DATALOG, nullptr, 0);
+ read_packet(PID_DATA, info, sizeof(info), sizeof(info), false);
+
+ unsigned int flash_start_addr = le_read32(info);
+ unsigned int flash_length = le_read32(info + 4);
+ unsigned int data_start_addr = le_read32(info + 8);
+ unsigned int next_blank_addr = le_read32(info + 12);
+
+ if (data_start_addr > next_blank_addr) {
+ /* usually there are two segments to be read */
+ *seg1_addr = data_start_addr;
+ *seg1_len = flash_start_addr + flash_length - *seg1_addr;
+ *seg2_addr = flash_start_addr;
+ *seg2_len = next_blank_addr - flash_start_addr;
+ } else {
+ /* hasn't wrapped around yet, only one segment */
+ *seg1_addr = data_start_addr;
+ *seg1_len = next_blank_addr - data_start_addr;
+ *seg2_addr = 0;
+ *seg2_len = 0;
+ }
+
+ if (*seg1_len & 0x1F || *seg2_len & 0x1F) {
+ fatal(MYNAME ": Protocol error: datalog lengths %u, %u "
+ "not aligned to 32 bytes\n", *seg1_len, *seg2_len);
+ }
+}
+
+static void
+read_datalog_records(route_head* track,
+ unsigned int start_addr, unsigned int len)
+{
+ unsigned char payload[7];
+
+ /* The protocol only supports reading 256 logpoints at once, so
+ * read small chunks until none left. */
+ while (len > 0) {
+ unsigned char logpoints[MAX_READ_LOGPOINTS * SBP_RECORD_LEN];
+ unsigned int logpoints_len = len > MAX_READ_LOGPOINTS ? MAX_READ_LOGPOINTS : len;
+
+ le_write32(payload, start_addr);
+ le_write16(payload + 4, logpoints_len);
+ payload[6] = 0x01;
+
+ write_packet(PID_READ_DATALOG, payload, sizeof(payload));
+ read_packet(PID_DATA, logpoints, logpoints_len, logpoints_len, false);
+ write_packet(PID_ACK, nullptr, 0);
+
+ for (unsigned char* p = logpoints; p < logpoints + logpoints_len; p += 32) {
+ track_add_wpt(track, navilink_decode_logpoint(p));
+ }
+
+ len -= logpoints_len;
+ start_addr += logpoints_len;
+ }
+}
+
+static void
+serial_read_datalog()
+{
+ unsigned int seg1_addr;
+ unsigned int seg1_len;
+ unsigned int seg2_addr;
+ unsigned int seg2_len;
+
+ read_datalog_info(&seg1_addr, &seg1_len, &seg2_addr, &seg2_len);
+
+ auto* track = new route_head;
+ track_add_head(track);
+
+ if (seg1_len) {
+ read_datalog_records(track, seg1_addr, seg1_len);
+ }
+
+ if (seg2_len) {
+ read_datalog_records(track, seg2_addr, seg2_len);
+ }
+}
+
+static void
+file_read()
+{
+ unsigned char data[32];
+ route_head* track = nullptr;
+
+ while (gbfread(data, sizeof(data), 1, file_handle) == 1) {
+ switch (le_read16(data)) {
+ case 0x2000:
+ fatal(MYNAME ": Route objects not supported in file sources\n");
+ break;
+ case 0x2010:
+ fatal(MYNAME ": Subroute objects not supported in file sources\n");
+ break;
+ case 0x4000:
+ if (global_opts.masked_objective & WPTDATAMASK) {
+ waypt_add(decode_waypoint(data));
+ }
+ break;
+ default:
+ if (global_opts.masked_objective & TRKDATAMASK) {
+ if (track == nullptr) {
+ track = new route_head;
+ track_add_head(track);
+ }
+
+ track_add_wpt(track, decode_trackpoint(data));
+ }
+ break;
+ }
+ }
+}
+
+static void
+file_write_waypoint(const Waypoint* waypt)
+{
+ unsigned char data[32];
+
+ encode_waypoint(waypt, data);
+ gbfwrite(data, sizeof(data), 1, file_handle);
+}
+
+static void
+file_write_track_start(const route_head*)
+{
+ track_serial = 1;
+}
+
+static void
+file_write_track_point(const Waypoint* waypt)
+{
+ unsigned char data[32];
+
+ encode_trackpoint(waypt, track_serial++, data);
+ gbfwrite(data, sizeof(data), 1, file_handle);
+}
+
+static void
+file_write_track_end(const route_head*)
+{
+}
+
+static void
+file_write_route_start(const route_head*)
+{
+ fatal(MYNAME ": Can't write routes to a file\n");
+}
+
+static void
+file_write_route_point(const Waypoint*)
+{
+}
+
+static void
+file_write_route_end(const route_head*)
+{
+}
+
+static void
+nuke()
+{
+ if (nuketrk) {
+ unsigned char information[32];
+ unsigned char data[7];
+
+ write_packet(PID_QRY_INFORMATION, nullptr, 0);
+ read_packet(PID_DATA, information,
+ sizeof(information), sizeof(information),
+ false);
+
+ le_write32(data + 0, le_read32(information + 4));
+ le_write16(data + 4, 0);
+ data[6] = 0;
+
+ write_packet(PID_ERASE_TRACK, data, sizeof(data));
+ read_packet(PID_CMD_OK, nullptr, 0, 0, false);
+ }
+
+ if (nukerte) {
+ unsigned char data[4];
+
+ le_write32(data, 0x00f00000);
+ write_packet(PID_DEL_ALL_ROUTE, data, sizeof(data));
+ if (!read_packet(PID_ACK, nullptr, 0, 0, true)) {
+ fatal(MYNAME ": Could not nuke all routes.\n");
+ }
+ }
+
+ if (nukewpt) {
+ unsigned char data[4];
+
+ le_write32(data, 0x00f00000);
+ write_packet(PID_DEL_ALL_WAYPOINT, data, sizeof(data));
+ if (!read_packet(PID_ACK, nullptr, 0, 0, true)) {
+ fatal(MYNAME ": You must nuke all routes before nuking waypoints.\n");
+ /* perhaps a better action would be to nuke routes for user.
+ * i.e. set nukerte when nukewpt is set */
+ }
+ }
+
+ if (nukedlg) {
+ write_packet(PID_CLEAR_DATALOG, nullptr, 0);
+ /* The flash erase operation is time-consuming. Each sector (64KB)
+ * takes around 1 second. The total sectors for SBP is 10.
+ * So give the device some time to clear its datalog, in addition
+ * to SERIAL_TIMEOUT, which applies to read_packet() */
+ QThread::usleep(CLEAR_DATALOG_TIME * 1000);
+ read_packet(PID_ACK, nullptr, 0, 0, false);
+ }
+}
+
+static void
+navilink_common_init(const QString& name)
+{
+ if (gbser_is_serial(qPrintable(name))) {
+ if ((serial_handle = gbser_init(qPrintable(name))) == nullptr) {
+ fatal(MYNAME ": Could not open serial port %s\n", qPrintable(name));
+ }
+
+ if (gbser_set_port(serial_handle, 115200, 8, 0, 1) != gbser_OK) {
+ fatal(MYNAME ": Can't configure port\n");
+ }
+
+ write_packet(PID_SYNC, nullptr, 0);
+ read_packet(PID_ACK, nullptr, 0, 0, false);
+
+ /* nuke data before writing */
+ if (operation == WRITING) {
+ nuke();
+ }
+
+ write_waypoint = serial_write_waypoint;
+ write_track_start = serial_write_track_start;
+ write_track_point = serial_write_track_point;
+ write_track_end = serial_write_track_end;
+ write_route_start = serial_write_route_start;
+ write_route_point = serial_write_route_point;
+ write_route_end = serial_write_route_end;
+ } else {
+ const char* mode = operation == READING ? "r" : "wb";
+ file_handle = gbfopen(name, mode, MYNAME);
+
+ write_waypoint = file_write_waypoint;
+ write_track_start = file_write_track_start;
+ write_track_point = file_write_track_point;
+ write_track_end = file_write_track_end;
+ write_route_start = file_write_route_start;
+ write_route_point = file_write_route_point;
+ write_route_end = file_write_route_end;
+ }
+
+}
+
+static void
+navilink_rd_init(const QString& name)
+{
+ operation = READING;
+ navilink_common_init(name);
+}
+
+static void
+navilink_wr_init(const QString& name)
+{
+ operation = WRITING;
+ navilink_common_init(name);
+}
+
+static void
+navilink_deinit()
+{
+ if (serial_handle) {
+ /* nuke data after reading */
+ if (operation == READING) {
+ nuke();
+ }
+
+ if (poweroff) {
+ write_packet(PID_QUIT, nullptr, 0);
+ }
+
+ gbser_deinit(serial_handle);
+ }
+
+ if (file_handle) {
+ gbfclose(file_handle);
+ }
+
+}
+
+static void
+navilink_read()
+{
+ if (datalog) {
+ if (global_opts.masked_objective & TRKDATAMASK) {
+ if (serial_handle) {
+ serial_read_datalog();
+ } else if (file_handle) {
+ fatal(MYNAME ": Not supported. Use SBP format.\n");
+ }
+ }
+ } else {
+ if (serial_handle) {
+ Waypoint** waypts = nullptr;
+
+ if (global_opts.masked_objective & (WPTDATAMASK|RTEDATAMASK)) {
+ waypts = serial_read_waypoints();
+ }
+
+ if (global_opts.masked_objective & TRKDATAMASK) {
+ serial_read_track();
+ }
+
+ if (global_opts.masked_objective & RTEDATAMASK) {
+ serial_read_routes(waypts);
+ }
+
+ if (waypts) {
+ free_waypoints(waypts);
+ }
+ } else if (file_handle) {
+ file_read();
+ }
+ }
+}
+
+static void
+navilink_write()
+{
+ if (datalog) {
+ fatal(MYNAME ": Writing to datalog not supported.\n");
+ }
+
+ switch (global_opts.objective) {
+ case trkdata:
+ track_disp_all(write_track_start,
+ write_track_end,
+ write_track_point);
+ break;
+ case wptdata:
+ waypt_disp_all(write_waypoint);
+ break;
+ case rtedata:
+ if (serial_handle) {
+ route_waypts = serial_read_waypoints();
+ }
+ route_disp_all(write_route_start,
+ write_route_end,
+ write_route_point);
+ if (route_waypts) {
+ free_waypoints(route_waypts);
+ route_waypts = nullptr;
+ }
+ break;
+ default:
+ fatal(MYNAME ": Unknown objective.\n");
+ }
+}
+
+ff_vecs_t navilink_vecs = {
+ ff_type_serial,
+ FF_CAP_RW_ALL,
+ navilink_rd_init,
+ navilink_wr_init,
+ navilink_deinit,
+ navilink_deinit,
+ navilink_read,
+ navilink_write,
+ nullptr,
+ &navilink_args,
+ NULL_POS_OPS
+};
--- /dev/null
+/*
+ Locosys NaviGPS GT-31/BGT-31 common functions.
+
+ Copyright (C) 2008 Rodney Lorrimar <rodney@rodney.id.au>
+ Copyright (C) 2005 Robert Lipe, robertlipe@usa.net
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ */
+
+#ifndef NAVILINK_H_INCLUDED_
+#define NAVILINK_H_INCLUDED_
+
+#include <ctime>
+#include "defs.h"
+
+#define SBP_RECORD_LEN 32
+
+/* defined in navilink.c */
+Waypoint* navilink_decode_logpoint(const unsigned char* buffer);
+unsigned navilink_checksum_packet(const unsigned char* packet, unsigned length);
+
+/* defined in sbn.c */
+bool locosys_decode_file_id(char* header, size_t len);
+
+
+#ifdef THIS_IS_ONLY_FOR_REFERENCE
+/* Locosys SBP and SBN structures */
+
+typedef __packed struct {
+ UINT8 HDOP; /* HDOP [0..51] with resolution 0.2 */
+ UINT8 SVIDCnt; /* Number of SVs in solution [0 to 12] */
+ UINT16 UtcSec; /* UTC Second [0 to 59] in seconds with resolution 0.001 */
+ UINT32 date_time_UTC_packed; /* refer to protocol doc*/
+ UINT32 SVIDList; /* SVs in solution: Bit 0=1: SV1, Bit 1=1: SV2, ... , Bit 31=1: SV32 */
+ INT32 Lat; /* Latitude [-90 to 90] in degrees with resolution 0.0000001 */
+ INT32 Lon; /* Longitude [-180 to 180] in degrees with resolution 0.0000001 */
+ INT32 AltCM; /* Altitude from Mean Sea Level in centi meters */
+ UINT16 Sog; /* Speed Over Ground in m/sec with resolution 0.01 */
+ UINT16 Cog; /* Course Over Ground [0 to 360] in degrees with resolution 0.01 */
+ INT16 ClmbRte; /* Climb rate in m/sec with resolution 0.01 */
+ UINT8 bitFlags; /* bitFlags, default 0x00, bit 0=1 indicate the first point after power on */
+ UINT8 reserved;
+} T_SBP;
+
+typedef struct __packed {
+ UINT8 Mid;
+ UINT16 Valid;
+ UINT16 Mode; /* Nav Mode: bit map as follows:
+ * Bits 2-0: GPS Fix Type
+ * 000 = No Nav
+ * 001 = 1 SV solution
+ * 010 = 2 SV solution
+ * 011 = 3 SV solution (2D)
+ * 100 = 4 or more SV solution (3D)
+ * 101 = Least Square 2D solution
+ * 110 = Least Square 3D solution
+ * 111 = DR solution (no SV)
+ * Bit 3 : 1 = Trickle Power ON
+ * Bits 5-4: Altitude Hold
+ * 00 = No Altitude Hold
+ * 01 = Altitude Hold using altitude from KF
+ * 10 = Altitude Hold using altitude from user
+ * 11 = forced altitude
+ * Bit 6 : 1 = DOP exceeded
+ * Bit 7 : 1 = DGPS correction applied
+ * Bit 8 :
+ * 1 = Sensor-based DR
+ * 0 = Velocity DR, if bits 2-0 = 111
+ * = see bits 15-14, if bits 2-0 != 111
+ * Bit 9 : 1 = Solution validated
+ * Bit 10 : 1 = Velocity DR Timeout
+ * Bit 11 : 1 = Solution edited by UI
+ * Bit 12 : 1 = Velocity invalid
+ * Bit 13 : 1 = Altitude Hold disabled
+ * Bits 15-14: SiRFDrive DR Status (applicable only when bit 8=0)
+ * 00 = GPS Only
+ * 01 = Calibrating
+ * 10 = DR sensor error
+ * 11 = DR Test mode
+ */
+ UINT16 Week; /* Extended Week Number */
+ UINT32 TOW; /* Time of Week [0 to 604800] in seconds with resolution 0.001 */
+ UINT16 UtcYr; /* UTC Year [1980 to 3000] */
+ UINT8 UtcMth; /* UTC Month [1 to 12] */
+ UINT8 UtcDay; /* UTC Day [1 to 31] */
+ UINT8 UtcHr; /* UTC Hour [0 to 23] */
+ UINT8 UtcMin; /* UTC Minute [0 to 59] */
+ UINT16 UtcSec; /* UTC Second [0 to 59] in seconds with resolution 0.001 */
+ UINT32 SVIDList; /* SVs in solution: Bit 0=1: SV1, Bit 1=1: SV2, ... , Bit 31=1: SV32 */
+
+ INT32 Lat; /* Latitude [-90 to 90] in degrees with resolution 0.0000001 */
+ INT32 Lon; /* Longitude [-180 to 180] in degrees with resolution 0.0000001 */
+ INT32 AltE; /* Altitude from Ellipsoid in meters with resolution 0.01 */
+ INT32 AltM; /* Altitude from Mean Sea Level in meters with resolution 0.01 */
+ UINT8 Datum; /* Map datum */
+ UINT16 Sog; /* Speed Over Ground in m/sec with resolution 0.01 */
+ UINT16 Cog; /* Course Over Ground [0 to 360] in degrees with resolution 0.01 */
+ INT16 MagVar; /* Magnetic Variation - Reserved */
+ INT16 ClmbRte; /* Climb rate in m/sec with resolution 0.01 */
+ INT16 HdRte; /* Heading Rate in deg/sec with resolution 0.01 (SiRFDrive only) */
+ UINT32 Ehpe; /* Expected Horizontal Position Error in meters with resolution 0.01 */
+ UINT32 Evpe; /* Expected Horizontal Vertical Error in meters with resolution 0.01 */
+ UINT32 Ete; /* Expected Time Error in meters with resolution 0.01 (SiRFDrive only) - Reserved */
+ UINT16 Ehve; /* Expected Horizontal Velocity Error in m/sec with resolution 0.01 (SiRFDrive only) */
+ INT32 ClkBias; /* Clock Bias in meters with resolution 0.01 */
+ UINT32 ClkBiasE; /* Clock Bias Error in meters with resolution 0.01 (SiRFDrive only) */
+ INT32 ClkDrift; /* Clock Drift in m/sec with resolution 0.01 */
+ UINT32 ClkDriftE; /* Clock Drift in m/sec with resolution 0.01 (SiRFDrive only) */
+ UINT32 Trvled; /* Distance Traveled since reset in meters (SiRFDrive only) */
+ UINT16 TrvledE; /* Distance Traveled Error in meters (SiRFDrive only) */
+ UINT16 HdE; /* Heading Error [0 to 180] in degrees with resolution 0.01 (SiRFDrive only) */
+ UINT8 SVIDCnt; /* Number of SVs in solution [0 to 12] */
+ UINT8 HDOP; /* HDOP [0..51] with resolution 0.2 */
+ UINT8 Reserved; /* Reserved */
+
+ UINT16 ufSog; /* Speed Over Ground in m/sec with resolution 0.01 ,unfiltered*/
+ UINT16 ufCog; /* Course Over Ground [0 to 360] in degrees with resolution 0.01, unfiltered */
+
+} T_SBN_REC;
+
+#endif
+
+#endif // NAVILINK_H_INCLUDED_
--- /dev/null
+/*
+ Locosys NaviGPS GT-31/BGT-31 SiRF binary logging format (SBN)
+
+ Copyright (C) 2008 Rodney Lorrimar <rodney@rodney.id.au>
+ Copyright (C) 2005 Robert Lipe, robertlipe+source@gpsbabel.org
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <cstring> // for size_t, memcpy
+
+#include <QDate> // for QDate
+#include <QDateTime> // for QDateTime
+#include <QTime> // for QTime
+#include <QString> // for QString
+#include <QVector> // for QVector
+#include <QtGlobal> // for Q_UNUSED
+#include <Qt> // for UTC
+
+#include "defs.h"
+#include "gbfile.h" // for gbfread, gbfclose, gbfeof, gbfopen
+#include "navilink.h" // for navilink_checksum_packet, locosys_...
+
+
+#define MYNAME "sbn"
+
+static gbfile* file_handle = nullptr;
+
+static
+QVector<arglist_t> sbn_args = {
+};
+
+
+/**********************************************************************/
+
+/* Packets are encoded according to the SiRF Binary Protocol.
+ *
+ * http://www.navmanwirelessoem.com/oem/customer-support/oem-ne
+ * ws/product-briefs-and-data-sheets/jupiter-32-xlp-new2/sirf-b
+ * inary-protocol-reference-manual
+ *
+ * The important packet is "Geodetic Navigation Data" (Message ID 41).
+ */
+
+#define PID_SBN 41
+#define SBN_RECORD_LEN 97 /* 91 plus three two shorts added by Locosys */
+/* V1.3 of the s/w added SDOP and and VSDOP bytes */
+#define PID_VISIBLE_LIST 13
+#define PID_QRY_INFORMATION 253
+#define QRY_INFORMATION_LEN 41
+#define INFO_USERNAME_LEN 13
+#define INFO_SERIAL_NUM_LEN 9
+#define INFO_LOG_RATE_LEN 3
+#define INFO_VERSION_LEN 12
+#define INFO_SEP ','
+
+
+/*
+ * Very similar to read_packet in navilink.c, except reads from file
+ * instead of serial, and integers are read in big endian order.
+ */
+static size_t
+read_packet(int* type, void* payload, size_t max_len)
+{
+ unsigned char start[4];
+
+ if (gbfread(start, sizeof(start), 1, file_handle) != 1) {
+ if (gbfeof(file_handle)) {
+ return 0;
+ }
+
+ fatal(MYNAME ": Format error: No packet start.\n");
+ }
+
+ if (start[0] != 0xa0 || start[1] != 0xa2) {
+ fatal(MYNAME ": Format error: Bad packet start.\n");
+ }
+
+ size_t size = be_readu16(start + 2);
+
+ if (size < 1 || max_len < size) {
+ fatal(MYNAME ": Format error: unexpected size: %d.\n", (int) size);
+ }
+
+ /* allocate space for checksum and trailing 0xb0b3 */
+ size_t data_size = size + 4;
+
+ /* data_size can be up to about 64k */
+ auto* data = (unsigned char*) xmalloc(data_size);
+
+ if (gbfread(data, data_size, 1, file_handle) != 1) {
+ fatal(MYNAME ": Format error: could not read %d bytes.\n",
+ (int) data_size);
+ }
+
+ *type = data[0];
+
+ unsigned int checksum_exp = be_readu16(data + size);
+ unsigned int checksum_act = navilink_checksum_packet(data, size);
+
+ if (checksum_exp != checksum_act) {
+ fatal(MYNAME ": Checksum error - expected %x got %x\n",
+ checksum_exp, checksum_act);
+ }
+
+ if (data[size + 2] != 0xb0 || data[size + 3] != 0xb3) {
+ fatal(MYNAME ": Format error: Bad packet trailer\n");
+ }
+
+ --size;
+
+ memcpy(payload, data + 1, size);
+ xfree(data);
+
+ return size;
+}
+
+#ifdef LOCOSYS_PARSE_FILE_ID
+static size_t
+hdrcpy(char* dest, const char* src, size_t max_len)
+{
+ size_t i;
+
+ for (i = 0; i < max_len && *src != INFO_SEP; i++) {
+ *dest++ = *src++;
+ }
+ *dest++ = 0;
+
+ return ++i;
+}
+#endif /* LOCOSYS_PARSE_FILE_ID */
+
+bool
+locosys_decode_file_id(char* header, size_t len)
+{
+ Q_UNUSED(header);
+ Q_UNUSED(len);
+#ifdef LOCOSYS_PARSE_FILE_ID
+ /*
+ * MID_FILE_ID(0xfd) contains the following payload :
+ * User Name, Serial Number, Log Rate, Firmware Version
+ * >field separator:","
+ * >User Name : MAX CHAR(13)
+ * >Serial Number : MAX CHAR(8)
+ * >Log Rate : MAX CHAR 3, 0..255 in seconds
+ * >Firmware Version : MAX CHAR (13)
+ */
+
+ char username[INFO_USERNAME_LEN + 1];
+ char serial_num[INFO_SERIAL_NUM_LEN + 1];
+ char log_rate[INFO_LOG_RATE_LEN + 1];
+ char version[INFO_VERSION_LEN + 1];
+ char* p = header;
+
+ p += hdrcpy(username, p, INFO_USERNAME_LEN);
+ p += hdrcpy(serial_num, p, INFO_SERIAL_NUM_LEN);
+ p += hdrcpy(log_rate, p, INFO_LOG_RATE_LEN);
+ p += hdrcpy(version, p, INFO_VERSION_LEN);
+
+ printf(MYNAME ": Username: %s\n", username);
+ printf(MYNAME ": Serial Number: %s\n", serial_num);
+ printf(MYNAME ": Log rate (seconds): %s\n", log_rate);
+ printf(MYNAME ": Firmware version: %s\n", version);
+#endif /* LOCOSYS_PARSE_FILE_ID */
+
+ return true;
+}
+
+static void
+read_sbn_header(route_head*)
+{
+ char header[QRY_INFORMATION_LEN];
+ int type = 0;
+
+ size_t len = read_packet(&type, header, sizeof(header));
+
+ if (len == 0 || type != PID_QRY_INFORMATION ||
+ !locosys_decode_file_id(header, len)) {
+ fatal(MYNAME ": Format error: Couldn't read SBN header."
+ "This probably isn't a SBN file.\n");
+ }
+}
+
+static int
+is_sbn_valid(const unsigned char* buffer)
+{
+ /* valid navigation (any bit set implies navigation solution is not
+ * optimal) */
+ return !buffer[0] && !buffer[1];
+}
+
+static fix_type
+decode_sbn_mode(const unsigned char* mode)
+{
+ static const fix_type fixes[8] = {
+ fix_none, /* 000 No Nav */
+ fix_none, /* 001 1 SV solution */
+ fix_none, /* 010 2 SV solution */
+ fix_2d, /* 011 3 SV solution (2D) */
+ fix_3d, /* 100 4 or more SV solution (3D) */
+ fix_2d, /* 101 Least Square 2D solution */
+ fix_3d, /* 110 Least Square 3D solution */
+ fix_none /* 111 DR solution (no SV) */
+ };
+ int dgps_correction = *mode & 0x80;
+ fix_type fix = fixes[*mode & 7];
+
+ return dgps_correction && fix == fix_3d ? fix_dgps : fix;
+}
+
+static void
+decode_sbn_datetime(const unsigned char* buffer, Waypoint* waypt)
+{
+ int scaled_seconds = be_readu16(buffer + 6);
+
+ int ms = scaled_seconds % 1000;
+ int sec = scaled_seconds / 1000;
+ int min = buffer[5];
+ int hour = buffer[4];
+ int mday = buffer[3];
+ int mon = buffer[2];
+ int year = be_readu16(buffer);
+
+ waypt->SetCreationTime(QDateTime(QDate(year, mon, mday), QTime(hour, min, sec, ms), Qt::UTC));
+}
+
+static void
+decode_sbn_position(const unsigned char* buffer, Waypoint* waypt)
+{
+ waypt->latitude = be_read32(buffer + 0) * 0.0000001;
+ waypt->longitude = be_read32(buffer + 4) * 0.0000001;
+ waypt->altitude = be_read32(buffer + 12) * 0.01;
+}
+
+static Waypoint*
+decode_sbn_record(unsigned char* buffer)
+{
+ auto* waypt = new Waypoint;
+
+ if (is_sbn_valid(buffer)) {
+ waypt->fix = decode_sbn_mode(buffer + 3);
+ } else {
+ waypt->fix = fix_none;
+ }
+
+ decode_sbn_datetime(buffer + 10, waypt);
+ decode_sbn_position(buffer + 22, waypt);
+ waypt->set_speed(be_read16(buffer + 39) * 0.01f);
+ waypt->set_course(be_read16(buffer + 41) * 0.01f);
+ waypt->sat = buffer[87];
+ waypt->hdop = buffer[88] * 0.2f;
+
+ return waypt;
+}
+
+static void
+add_logpoints(route_head* track)
+{
+ unsigned char buffer[SBN_RECORD_LEN];
+ int type = 0;
+
+ while (read_packet(&type, buffer, sizeof(buffer))) {
+ if (type == PID_SBN) {
+ track_add_wpt(track, decode_sbn_record(buffer));
+ } else if (type == PID_VISIBLE_LIST) {
+ /* A list of visible SVs, their IDs, azimuths, elevations.
+ * Not storing this info for now. */
+ } else {
+ warning(MYNAME ": Format error: Unknown packet type 0x%02x.\n", type);
+ }
+ }
+}
+
+/**********************************************************************/
+
+static void
+sbn_rd_init(const QString& fname)
+{
+ file_handle = gbfopen(fname, "r", MYNAME);
+}
+
+static void
+sbn_rd_deinit()
+{
+ gbfclose(file_handle);
+}
+
+static void
+sbn_read()
+{
+ if (global_opts.masked_objective & TRKDATAMASK) {
+ auto* track = new route_head;
+ track_add_head(track);
+
+ read_sbn_header(track);
+
+ add_logpoints(track);
+ }
+}
+
+/**********************************************************************/
+
+/* Characters are always encoded in ASCII. Even if the unit is set
+ * to Chinese language, only ASCII characters can be entered.
+ */
+
+ff_vecs_t sbn_vecs = {
+ ff_type_file,
+ {
+ ff_cap_none /* waypoints */,
+ ff_cap_read /* tracks */,
+ ff_cap_none /* routes */
+ },
+ sbn_rd_init,
+ nullptr,
+ sbn_rd_deinit,
+ nullptr,
+ sbn_read,
+ nullptr,
+ nullptr,
+ &sbn_args,
+ NULL_POS_OPS
+};
+/**********************************************************************/
--- /dev/null
+/*
+ Locosys NaviGPS GT-31/BGT-31 binary datalog format (SBP)
+
+ Copyright (C) 2008 Rodney Lorrimar <rodney@rodney.id.au>
+ Copyright (C) 2005 Robert Lipe, robertlipe+source@gpsbabel.org
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ */
+
+#include <cstddef> // for size_t
+
+#include <QString> // for QString
+#include <QVector> // for QVector
+
+#include "defs.h"
+#include "gbfile.h" // for gbfread, gbfclose, gbfopen, gbfile
+#include "navilink.h" // for locosys_decode_file_id, navilink_decode_logpoint
+
+
+#define MYNAME "sbp"
+
+static gbfile* file_handle = nullptr;
+
+static
+QVector<arglist_t> sbp_args = {
+};
+
+/*******************************************************************************
+* %%% global callbacks called by gpsbabel main process %%% *
+*******************************************************************************/
+
+static void
+sbp_rd_init(const QString& fname)
+{
+ file_handle = gbfopen(fname, "r", MYNAME);
+}
+
+static void
+sbp_rd_deinit()
+{
+ gbfclose(file_handle);
+}
+
+static void
+read_sbp_header(route_head*)
+{
+ /*
+ * A complete SBP file contains 64 bytes header,
+ *
+ * Here is the definition of the SBP header
+ * BYTE 0 ~1 : true SBP header length
+ * BYTE 2~63: MID_FILE_ID(0xfd)
+ * will stuff 0xff for remaining bytes
+ */
+
+#define HEADER_SKIP 7
+
+ bool success;
+ char header[64];
+
+ if (gbfread(header, sizeof(header), 1, file_handle) == 1) {
+ size_t len = le_read16(header) - HEADER_SKIP;
+ if (len > sizeof(header)) {
+ len = sizeof(header);
+ }
+
+ success = locosys_decode_file_id(header + HEADER_SKIP, len);
+ } else {
+ success = false;
+ }
+
+ if (!success) {
+ fatal(MYNAME ": Format error: Couldn't read SBP header."
+ "This probably isn't a SBP file.\n");
+ }
+}
+
+static Waypoint*
+read_logpoint()
+{
+ unsigned char buffer[SBP_RECORD_LEN];
+
+ if (gbfread(buffer, sizeof(buffer), 1, file_handle) == 1) {
+ return navilink_decode_logpoint(buffer);
+ }
+
+ return nullptr;
+}
+
+static void
+sbp_read()
+{
+ Waypoint* logpoint;
+
+ auto* track = new route_head;
+ track_add_head(track);
+
+ read_sbp_header(track);
+
+ while ((logpoint = read_logpoint())) {
+ track_add_wpt(track, logpoint);
+ }
+}
+
+/**************************************************************************/
+
+/* ascii is the expected character set */
+/* not fixed, can be changed through command line parameter */
+
+ff_vecs_t sbp_vecs = {
+ ff_type_file,
+ {
+ ff_cap_none /* waypoints */,
+ ff_cap_read /* tracks */,
+ ff_cap_none /* routes */
+ },
+ sbp_rd_init,
+ nullptr,
+ sbp_rd_deinit,
+ nullptr,
+ sbp_read,
+ nullptr,
+ nullptr,
+ &sbp_args,
+ NULL_POS_OPS
+};
+/**************************************************************************/
+++ /dev/null
-/*
- NaviGPS serial protocol.
-
- Copyright (C) 2007 Tom Hughes, tom@compton.nu
- Copyright (C) 2008 Rodney Lorrimar, rodney@rodney.id.au
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-
- */
-
-
-/* Based on description at http://wiki.splitbrain.org/navilink */
-
-#include <cstdio> // for fprintf, stderr
-#include <cstring> // for memcpy, memset, strncpy
-
-#include <QByteArray> // for QByteArray
-#include <QDate> // for QDate
-#include <QDateTime> // for QDateTime
-#include <QString> // for QString, operator==
-#include <QThread> // for QThread
-#include <QTime> // for QTime
-#include <QVector> // for QVector
-#include <QtCore> // for qRound, qPrintable, UTC
-
-#include "defs.h"
-#include "navilink.h"
-#include "gbfile.h" // for gbfwrite, gbfclose, gbfopen, gbfread
-#include "gbser.h" // for gbser_read_wait, gbser_deinit, gbs...
-#include "jeeps/gpsmath.h" // for GPS_Math_WGS84_To_UTM_EN
-#include "jeeps/gpsport.h" // for int32
-#include "src/core/datetime.h" // for DateTime
-
-
-#define MYNAME "NAVILINK"
-
-static char* nuketrk = nullptr;
-static char* nukerte = nullptr;
-static char* nukewpt = nullptr;
-static char* nukedlg = nullptr;
-static char* poweroff = nullptr;
-static char* datalog = nullptr;
-
-static void* serial_handle = nullptr;
-static gbfile* file_handle = nullptr;
-
-static unsigned char* track_data;
-static unsigned char* track_data_ptr;
-static unsigned char* track_data_end;
-static unsigned track_serial;
-static Waypoint** route_waypts;
-static unsigned* route_ids;
-static unsigned route_id_ptr;
-
-static enum {
- READING,
- WRITING
-} operation = READING;
-
-#define SERIAL_TIMEOUT 8000
-#define CLEAR_DATALOG_TIME 7000
-
-#define MAX_WAYPOINTS 1000
-#define MAX_SUBROUTES 9
-#define MAX_SUBROUTE_LENGTH 14
-#define MAX_ROUTE_LENGTH (MAX_SUBROUTES * MAX_SUBROUTE_LENGTH - 1)
-#define MAX_READ_TRACKPOINTS 512
-#define MAX_WRITE_TRACKPOINTS 127
-#define MAX_READ_LOGPOINTS 256
-
-#define PID_SYNC 0xd6
-#define PID_ACK 0x0c
-#define PID_NAK 0x00
-#define PID_QRY_INFORMATION 0x20
-#define PID_QRY_FW_VERSION 0xfe
-#define PID_DATA 0x03
-#define PID_ADD_A_WAYPOINT 0x3c
-#define PID_QRY_WAYPOINTS 0x28
-#define PID_QRY_ROUTE 0x24
-#define PID_DEL_WAYPOINT 0x36
-#define PID_DEL_ALL_WAYPOINT 0x37
-#define PID_DEL_ROUTE 0x34
-#define PID_DEL_ALL_ROUTE 0x35
-#define PID_ADD_A_ROUTE 0x3d
-#define PID_ERASE_TRACK 0x11
-#define PID_READ_TRACKPOINTS 0x14
-#define PID_WRITE_TRACKPOINTS 0x16
-#define PID_CMD_OK 0xf3
-#define PID_CMD_FAIL 0xf4
-#define PID_QUIT 0xf2
-#define PID_INFO_DATALOG 0x1c
-#define PID_READ_DATALOG 0x14
-#define PID_CLEAR_DATALOG 0x1b
-
-static
-const char* const icon_table[] = {
- "Star",
- "Flag",
- "House",
- "Left Sign",
- "Telegraph Pole",
- "People",
- "Fuel",
- "Phone",
- "Pole",
- "Mountain",
- "Water",
- "Tree",
- "Road Narrows",
- "Crossroads",
- "Road Fork",
- "Turn Right",
- "Turn Left",
- "Bird",
- "3D House",
- "Trig Point",
- "Tower",
- "Cable Car",
- "Church",
- "Telegraph Pole",
- "Skier",
- "Anchor",
- "Fish",
- "Fishes",
- "Rain",
- "Fisherman",
- "Tower",
- "Boats",
- "Boat",
- "Bicycle",
- "Railway Track",
- "Dollar Sign",
- "Bus",
- "Camera",
- "Fuel Pump",
- "Cup",
- "Merging Road",
- "Plane",
- "Red Cross",
- "House",
- "Parking"
-};
-
-static
-QVector<arglist_t> navilink_args = {
- {
- "nuketrk", &nuketrk, "Delete all track points", nullptr, ARGTYPE_BOOL,
- ARG_NOMINMAX, nullptr
- },
- {
- "nukerte", &nukerte, "Delete all routes", nullptr, ARGTYPE_BOOL,
- ARG_NOMINMAX, nullptr
- },
- {
- "nukewpt", &nukewpt, "Delete all waypoints", nullptr, ARGTYPE_BOOL,
- ARG_NOMINMAX, nullptr
- },
- {
- "nukedlg", &nukedlg, "Clear the datalog", nullptr, ARGTYPE_BOOL,
- ARG_NOMINMAX, nullptr
- },
- {
- "datalog", &datalog, "Read from datalogger buffer",
- nullptr, ARGTYPE_BOOL, ARG_NOMINMAX, nullptr
- },
- {
- "power_off", &poweroff, "Command unit to power itself down",
- nullptr, ARGTYPE_BOOL, ARG_NOMINMAX, nullptr
- },
-};
-
-static void (*write_waypoint)(const Waypoint*) = nullptr;
-static void (*write_track_start)(const route_head* track) = nullptr;
-static void (*write_track_point)(const Waypoint* waypt) = nullptr;
-static void (*write_track_end)(const route_head* track) = nullptr;
-static void (*write_route_start)(const route_head* track) = nullptr;
-static void (*write_route_point)(const Waypoint* waypt) = nullptr;
-static void (*write_route_end)(const route_head* track) = nullptr;
-
-static int
-find_icon_from_descr(const QString& descr)
-{
- for (unsigned int i = 0; i < sizeof(icon_table) / sizeof(const char*); i++) {
- if (0 == descr.compare(icon_table[i])) {
- return i;
- }
- }
-
- return 0;
-}
-
-static void
-free_waypoints(Waypoint** waypts)
-{
- for (Waypoint** wayptp = waypts; wayptp < waypts + MAX_WAYPOINTS; wayptp++) {
- if (*wayptp) {
- delete *wayptp;
- }
- }
-
- xfree(waypts);
-}
-
-static unsigned
-compare_waypoints(const Waypoint* waypt1, const Waypoint* waypt2)
-{
- return waypt1->latitude == waypt2->latitude &&
- waypt1->longitude == waypt2->longitude &&
- waypt1->altitude == waypt2->altitude &&
- waypt1->shortname == waypt2->shortname;
-}
-
-unsigned
-navilink_checksum_packet(const unsigned char* packet, unsigned length)
-{
- unsigned checksum = 0;
-
- while (length-- > 0) {
- checksum += *packet++;
- }
-
- return checksum & 0x7fff;
-}
-
-static void
-dump_packet(const char* prefix, unsigned char* packet, unsigned length)
-{
- unsigned i;
-
- for (i = 0; i < length; i++) {
- if ((i % 16) == 0) {
- fprintf(stderr, "%s %08x :", prefix, i);
- }
- fprintf(stderr, " %02x", packet[i]);
- if ((i % 16) == 15 || i == length - 1) {
- fprintf(stderr, "\n");
- }
- }
-
- fprintf(stderr, "\n");
-}
-
-static void
-write_packet(unsigned type, const void* payload, unsigned length)
-{
- auto* packet = (unsigned char*) xmalloc(length + 9);
-
- packet[0] = 0xa0;
- packet[1] = 0xa2;
- le_write16(packet + 2, length + 1);
- packet[4] = type;
- if (length > 0) {
- memcpy(packet + 5, payload, length);
- }
- le_write16(packet + length + 5, navilink_checksum_packet(packet + 4, length + 1));
- packet[length + 7] = 0xb0;
- packet[length + 8] = 0xb3;
-
- if (global_opts.debug_level >= 2) {
- dump_packet(">>>", packet + 4, length + 1);
- }
-
- if (gbser_write(serial_handle, packet, length + 9) != gbser_OK) {
- fatal(MYNAME ": Write error\n");
- }
-
- xfree(packet);
-}
-
-static unsigned
-read_word()
-{
- unsigned char buffer[2];
-
- if (gbser_read_wait(serial_handle, buffer, 2, SERIAL_TIMEOUT) != 2) {
- fatal(MYNAME ": Read error\n");
- }
-
- return (buffer[1] << 8) | buffer[0];
-}
-
-/*
- * Read a protocol packet into payload.
- *
- * handle_nak determines behaviour when a PID_NAK packet is read from
- * the device:
- * - if handle_nak is false, a fatal error will be raised.
- * - if handle_nak is true, read_packet will simply return false.
- *
- * Returns true if the packet was successfully read into payload.
- */
-static bool
-read_packet(unsigned type, void* payload,
- int minlength, int maxlength,
- bool handle_nak)
-{
- if (read_word() != 0xa2a0) {
- fatal(MYNAME ": Protocol error: Bad packet header."
- " Is your NaviGPS in NAVILINK mode?\n");
- }
-
- int size;
- if ((size = read_word()) <= minlength) {
- fatal(MYNAME ": Protocol error: Packet too short\n");
- }
-
- auto* data = (unsigned char*) xmalloc(size);
-
- if (gbser_read_wait(serial_handle, data, size, SERIAL_TIMEOUT) != size) {
- fatal(MYNAME ": Read error reading %d byte payload\n", size);
- }
-
- if (global_opts.debug_level >= 2) {
- dump_packet("<<<", data, size);
- }
-
- if (data[0] != type) {
- if (handle_nak && data[0] == PID_NAK) {
- return false;
- }
-
- fatal(MYNAME ": Protocol error: Bad packet type (expected 0x%02x but got 0x%02x)\n", type, data[0]);
- }
-
- unsigned checksum;
- if ((checksum = read_word()) != navilink_checksum_packet(data, size)) {
- fatal(MYNAME ": Checksum error - expected %x got %x\n",
- navilink_checksum_packet(data, size), checksum);
- }
-
- if (read_word() != 0xb3b0) {
- fatal(MYNAME ": Protocol error: Bad packet trailer\n");
- }
-
- if (size - 1 > maxlength) {
- memcpy(payload, data + 1, maxlength);
- } else {
- memcpy(payload, data + 1, size - 1);
- }
-
- xfree(data);
-
- return true;
-}
-
-static QDateTime
-decode_datetime(const unsigned char* buffer)
-{
- QTime tm(buffer[3], buffer[4], buffer[5]);
- QDate dt(2000 + buffer[0], buffer[1], buffer[2]);
- return QDateTime(dt, tm, Qt::UTC);
-}
-
-static void
-encode_datetime(const QDateTime& datetime, unsigned char* buffer)
-{
- if (datetime.isValid()) {
- QDateTime dt = datetime.toUTC();
- QDate date = dt.date();
- QTime time = dt.time();
- buffer[0] = date.year() - 2000;
- buffer[1] = date.month();
- buffer[2] = date.day();
- buffer[3] = time.hour();
- buffer[4] = time.minute();
- buffer[5] = time.second();
- } else {
- memset(buffer, 0, 6);
- }
-}
-
-static void
-decode_position(const unsigned char* buffer, Waypoint* waypt)
-{
- waypt->latitude = le_read32(buffer + 0) / 10000000.0;
- waypt->longitude = le_read32(buffer + 4) / 10000000.0;
- waypt->altitude = FEET_TO_METERS(le_read16(buffer + 8));
-}
-
-static void
-encode_position(const Waypoint* waypt, unsigned char* buffer)
-{
- le_write32(buffer + 0, qRound(waypt->latitude * 10000000));
- le_write32(buffer + 4, qRound(waypt->longitude * 10000000));
- le_write16(buffer + 8, qRound(METERS_TO_FEET(waypt->altitude)));
-}
-
-static unsigned
-decode_waypoint_id(const unsigned char* buffer)
-{
- unsigned id = le_read16(buffer + 2);
-
- if (id >= MAX_WAYPOINTS) {
- fatal(MYNAME ": Invalid waypoint ID\n");
- }
-
- return id;
-}
-
-static Waypoint*
-decode_waypoint(const unsigned char* buffer)
-{
- auto* waypt = new Waypoint;
-
- decode_position(buffer + 12, waypt);
- waypt->shortname = reinterpret_cast<const char*>(buffer) + 4;
- waypt->icon_descr = icon_table[buffer[28]];
- waypt->SetCreationTime(decode_datetime(buffer + 22));
-
- return waypt;
-}
-
-static void
-encode_waypoint(const Waypoint* waypt, unsigned char* buffer)
-{
- buffer[0] = 0x00;
- buffer[1] = 0x40;
- le_write16(buffer + 2, 0);
- strncpy((char*)buffer + 4, CSTRc(waypt->shortname), 6);
- buffer[10] = 0;
- buffer[11] = 0;
- encode_position(waypt, buffer + 12);
- encode_datetime(waypt->GetCreationTime(), buffer + 22);
- buffer[28] = find_icon_from_descr(waypt->icon_descr);
- buffer[29] = 0;
- buffer[30] = 0x00;
- buffer[31] = 0x7e;
-}
-
-static Waypoint*
-decode_trackpoint(const unsigned char* buffer)
-{
- auto* waypt = new Waypoint;
-
- decode_position(buffer + 12, waypt);
- waypt->SetCreationTime(decode_datetime(buffer + 22));
- waypt->set_course(le_read16(buffer + 2));
- waypt->set_speed(KPH_TO_MPS(buffer[29] * 2));
-
- return waypt;
-}
-
-static void
-encode_trackpoint(const Waypoint* waypt, unsigned serial, unsigned char* buffer)
-{
- double x;
- double y;
- int32 z;
- char zc;
-
- GPS_Math_WGS84_To_UTM_EN(waypt->latitude, waypt->longitude, &x, &y, &z, &zc);
-
- le_write16(buffer + 0, serial);
- le_write16(buffer + 2, qRound(waypt->course_value_or(0)));
- le_write32(buffer + 4, qRound(x));
- le_write32(buffer + 8, qRound(y));
- encode_position(waypt, buffer + 12);
- encode_datetime(waypt->GetCreationTime(), buffer + 22);
- buffer[28] = z;
- buffer[29] = qRound(MPS_TO_KPH(waypt->speed_value_or(0) / 2));
- buffer[30] = 0x5a;
- buffer[31] = 0x7e;
-}
-
-static Waypoint**
-serial_read_waypoints()
-{
- Waypoint** waypts = nullptr;
- unsigned char information[32];
-
- if (global_opts.masked_objective & RTEDATAMASK) {
- waypts = (Waypoint**) xcalloc(MAX_WAYPOINTS, sizeof(Waypoint*));
- }
-
- write_packet(PID_QRY_INFORMATION, nullptr, 0);
- read_packet(PID_DATA, information,
- sizeof(information), sizeof(information),
- false);
-
- unsigned short total = le_read16(information + 0);
-
- for (unsigned short start = 0; start < total; start += 32) {
- unsigned short count = total - start;
- unsigned char payload[7];
-
- if (count > 32) {
- count = 32;
- }
-
- le_write32(payload + 0, start);
- le_write16(payload + 4, count);
- payload[6] = 1;
-
- write_packet(PID_QRY_WAYPOINTS, payload, sizeof(payload));
-
- auto* waypoints = (unsigned char*) xmalloc(count * 32);
-
- read_packet(PID_DATA, waypoints, count * 32, count * 32, false);
-
- for (unsigned char* w = waypoints; w < waypoints + count * 32; w = w + 32) {
- if (global_opts.masked_objective & WPTDATAMASK) {
- waypt_add(decode_waypoint(w));
- }
- if (global_opts.masked_objective & RTEDATAMASK) {
- waypts[decode_waypoint_id(w)] = decode_waypoint(w);
- }
- }
-
- xfree(waypoints);
-
- if (global_opts.verbose_status) {
- waypt_status_disp(total, start + count);
- }
- }
-
- return waypts;
-}
-
-static unsigned int
-serial_write_waypoint_packet(const Waypoint* waypt)
-{
- unsigned char data[32];
- unsigned char id[2];
-
- encode_waypoint(waypt, data);
- write_packet(PID_ADD_A_WAYPOINT, data, sizeof(data));
- if (!read_packet(PID_DATA, id, sizeof(id), sizeof(id), true)) {
- fatal(MYNAME ": Could not write waypoint.\n");
- }
-
- return le_read16(id);
-}
-
-static void
-serial_write_waypoint(const Waypoint* waypt)
-{
- serial_write_waypoint_packet(waypt);
-}
-
-static void
-serial_read_track()
-{
- unsigned char information[32];
-
- write_packet(PID_QRY_INFORMATION, nullptr, 0);
- read_packet(PID_DATA, information,
- sizeof(information), sizeof(information),
- false);
-
- unsigned int address = le_read32(information + 4);
- unsigned short total = le_read16(information + 12);
-
- auto* track = new route_head;
- track_add_head(track);
-
- while (total > 0) {
- unsigned short count = total < MAX_READ_TRACKPOINTS ? total : MAX_READ_TRACKPOINTS;
- unsigned char payload[7];
-
- le_write32(payload + 0, address);
- le_write16(payload + 4, count * 32);
- payload[6] = 0x00;
-
- write_packet(PID_READ_TRACKPOINTS, payload, sizeof(payload));
-
- auto* trackpoints = (unsigned char*) xmalloc(count * 32);
-
- read_packet(PID_DATA, trackpoints, count * 32, count * 32, false);
- write_packet(PID_ACK, nullptr, 0);
-
- for (unsigned char* t = trackpoints; t < trackpoints + count * 32; t = t + 32) {
- track_add_wpt(track, decode_trackpoint(t));
- }
-
- xfree(trackpoints);
-
- address = address + count * 32;
- total = total - count;
- }
-}
-
-static void
-serial_write_track()
-{
- unsigned char information[32];
- unsigned char data[7];
-
- write_packet(PID_QRY_INFORMATION, nullptr, 0);
- read_packet(PID_DATA, information,
- sizeof(information), sizeof(information),
- false);
-
- unsigned int address = le_read32(information + 4);
- unsigned short total = le_read16(information + 12);
-
- le_write32(data + 0, address + total * 32);
- le_write16(data + 4, track_data_ptr - track_data);
- data[6] = 0x00;
-
- write_packet(PID_WRITE_TRACKPOINTS, data, sizeof(data));
- QThread::usleep(10000);
- write_packet(PID_DATA, track_data, track_data_ptr - track_data);
- read_packet(PID_CMD_OK, nullptr, 0, 0, false);
-
- track_data_ptr = track_data;
-}
-
-static void
-serial_write_track_start(const route_head*)
-{
- track_data = (unsigned char*) xmalloc(MAX_WRITE_TRACKPOINTS * 32);
- track_data_ptr = track_data;
- track_data_end = track_data + MAX_WRITE_TRACKPOINTS * 32;
-}
-
-static void
-serial_write_track_point(const Waypoint* waypt)
-{
- if (track_data_ptr >= track_data_end) {
- serial_write_track();
- }
-
- encode_trackpoint(waypt, 0, track_data_ptr);
-
- track_data_ptr += 32;
-}
-
-static void
-serial_write_track_end(const route_head*)
-{
- if (track_data_ptr > track_data) {
- serial_write_track();
- }
-
- xfree(track_data);
-}
-
-static void
-serial_read_routes(Waypoint** waypts)
-{
- unsigned char information[32];
-
- write_packet(PID_QRY_INFORMATION, nullptr, 0);
- read_packet(PID_DATA, information,
- sizeof(information), sizeof(information),
- false);
-
- unsigned char routec = information[2];
-
- for (unsigned char r = 0; r < routec; r++) {
- unsigned char payload[7];
- unsigned char routedata[320];
-
- le_write32(payload + 0, r);
- le_write16(payload + 2, 0);
- payload[6] = 0x01;
-
- write_packet(PID_QRY_ROUTE, payload, sizeof(payload));
- read_packet(PID_DATA, routedata, 64, sizeof(routedata), false);
-
- auto* route = new route_head;
- route->rte_num = routedata[2];
- route->rte_name = (char*)routedata + 4;
- route_add_head(route);
-
- for (int sr = 0; sr < MAX_SUBROUTES; sr++) {
- for (int w = 0; w < MAX_SUBROUTE_LENGTH; w++) {
- unsigned short id = le_read16(routedata + 34 + 32 * sr + 2 *w);
-
- if (id == 0xffffu) {
- w = MAX_SUBROUTE_LENGTH;
- sr = MAX_SUBROUTES;
- } else if (id >= MAX_WAYPOINTS) {
- fatal(MYNAME ": Invalid waypoint ID in route\n");
- } else if (waypts[id] == nullptr) {
- fatal(MYNAME ": Non-existent waypoint in route\n");
- } else {
- route_add_wpt(route, new Waypoint(*waypts[id]));
- }
- }
- }
- }
-}
-
-static void
-serial_write_route_start(const route_head* route)
-{
- route_ids = (unsigned int*) xmalloc(route->rte_waypt_ct() * sizeof(unsigned));
- route_id_ptr = 0;
-}
-
-static void
-serial_write_route_point(const Waypoint* waypt)
-{
- unsigned w;
-
- for (w = 0; w < MAX_WAYPOINTS; w++) {
- if (route_waypts[w] && compare_waypoints(waypt, route_waypts[w])) {
- break;
- }
- }
-
- if (w == MAX_WAYPOINTS) {
- w = serial_write_waypoint_packet(waypt);
- route_waypts[w] = new Waypoint(*waypt);
- }
-
- route_ids[route_id_ptr++] = w;
-}
-
-static void
-serial_write_route_end(const route_head* route)
-{
- unsigned char id[1];
-
- QString rte_name = route->rte_name;
- if (rte_name == nullptr) {
- rte_name = "NO NAME";
- }
- if (route_id_ptr > MAX_ROUTE_LENGTH) {
- fatal(MYNAME ": Route %s too long\n", qPrintable(route->rte_name));
- }
-
- unsigned src = (route_id_ptr + MAX_SUBROUTE_LENGTH) / MAX_SUBROUTE_LENGTH;
- auto* data = (unsigned char*) xmalloc(32 + src * 32);
-
- le_write16(data + 0, 0x2000);
- data[2] = 0;
- data[3] = 0x20;
- memset(data + 4, 0, 14);
- strncpy((char*)data + 4, CSTR(rte_name), 13);
- data[18] = 0;
- data[19] = 0;
- le_write32(data + 20, 0);
- le_write32(data + 24, 0);
- le_write16(data + 28, 0);
- data[30] = 0x7b;
- data[31] = 0x77;
-
- for (unsigned sr = 0; sr < src; sr++) {
- unsigned char* srdata = data + 32 + 32 * sr;
- unsigned pt_offset = MAX_SUBROUTE_LENGTH * sr;
-
- le_write16(srdata + 0, 0x2010);
-
- for (unsigned pt = 0; pt < MAX_SUBROUTE_LENGTH; pt++) {
- if (pt_offset + pt < route_id_ptr) {
- le_write16(srdata + 2 + 2 * pt, route_ids[pt_offset + pt]);
- } else {
- le_write16(srdata + 2 + 2 * pt, 0xffffu);
- }
- }
-
- srdata[30] = 0x7f;
- srdata[31] = 0x77;
- }
-
- write_packet(PID_ADD_A_ROUTE, data, 32 + src * 32);
- if (!read_packet(PID_DATA, id, sizeof(id), sizeof(id), true)) {
- fatal(MYNAME ": Could not add route.\n");
- }
-
- xfree(data);
- xfree(route_ids);
-}
-
-static int
-decode_sbp_msec(const unsigned char* buffer)
-{
- int msec = le_read16(buffer);
- return (msec % 1000);
-}
-
-static QDateTime
-decode_sbp_datetime_packed(const unsigned char* buffer)
-{
- /*
- * Packed_Date_Time_UTC:
- * bit 31..22 :year*12+month (10 bits) : real year= year+2000
- * bit17.21: day (5bits)
- * bit12.16: hour (5bits)
- * bit6..11: min (6bits)
- * bit0..5 : sec (6bits)
- *
- * 0 1 2 3
- * 01234567 01234567 01234567 01234567
- * ........ ........ ........ ........
- * SSSSSSMM MMMMHHHH Hdddddmm mmmmmmmm
- */
-
- int sec = buffer[0] & 0x3F;
- int min = ((buffer[0] & 0xC0) >> 6) | ((buffer[1] & 0x0F) << 2);
- int hour = ((buffer[1] & 0xF0) >> 4) | ((buffer[2] & 0x01) << 4);
- int mday = (buffer[2] & 0x3E) >> 1;
- int months = ((buffer[2] & 0xC0) >> 6) | buffer[3] << 2;
- int mon = months % 12;
- int year = 2000 + months / 12;
-
- return {QDate(year, mon, mday), QTime(hour, min, sec), Qt::UTC};
-}
-
-static void
-decode_sbp_position(const unsigned char* buffer, Waypoint* waypt)
-{
- waypt->latitude = le_read32(buffer + 0) / 10000000.0;
- waypt->longitude = le_read32(buffer + 4) / 10000000.0;
- waypt->altitude = le_read32(buffer + 8) / 100.0;
-}
-
-Waypoint*
-navilink_decode_logpoint(const unsigned char* buffer)
-{
- auto* waypt = new Waypoint;
-
- waypt->hdop = (buffer[0]) * 0.2f;
- waypt->sat = buffer[1];
- waypt->SetCreationTime(decode_sbp_datetime_packed(buffer + 4)
- .addMSecs(decode_sbp_msec(buffer + 2)));
- decode_sbp_position(buffer + 12, waypt);
- waypt->set_speed(le_read16(buffer + 24) * 0.01f);
- waypt->set_course(le_read16(buffer + 26) * 0.01f);
-
- return waypt;
-}
-
-/*
- * The datalog is a circular buffer, so it may be necessary to glue
- * together two segments. This function queries the device for the
- * circular buffer pointers, and returns two pairs of address/length.
- * If there is only one segment (i.e. the datalog has not yet wrapped
- * around), then seg2_addr and seg2_len will be zero.
- */
-static void
-read_datalog_info(unsigned int* seg1_addr, unsigned int* seg1_len,
- unsigned int* seg2_addr, unsigned int* seg2_len)
-{
- unsigned char info[16];
-
- write_packet(PID_INFO_DATALOG, nullptr, 0);
- read_packet(PID_DATA, info, sizeof(info), sizeof(info), false);
-
- unsigned int flash_start_addr = le_read32(info);
- unsigned int flash_length = le_read32(info + 4);
- unsigned int data_start_addr = le_read32(info + 8);
- unsigned int next_blank_addr = le_read32(info + 12);
-
- if (data_start_addr > next_blank_addr) {
- /* usually there are two segments to be read */
- *seg1_addr = data_start_addr;
- *seg1_len = flash_start_addr + flash_length - *seg1_addr;
- *seg2_addr = flash_start_addr;
- *seg2_len = next_blank_addr - flash_start_addr;
- } else {
- /* hasn't wrapped around yet, only one segment */
- *seg1_addr = data_start_addr;
- *seg1_len = next_blank_addr - data_start_addr;
- *seg2_addr = 0;
- *seg2_len = 0;
- }
-
- if (*seg1_len & 0x1F || *seg2_len & 0x1F) {
- fatal(MYNAME ": Protocol error: datalog lengths %u, %u "
- "not aligned to 32 bytes\n", *seg1_len, *seg2_len);
- }
-}
-
-static void
-read_datalog_records(route_head* track,
- unsigned int start_addr, unsigned int len)
-{
- unsigned char payload[7];
-
- /* The protocol only supports reading 256 logpoints at once, so
- * read small chunks until none left. */
- while (len > 0) {
- unsigned char logpoints[MAX_READ_LOGPOINTS * SBP_RECORD_LEN];
- unsigned int logpoints_len = len > MAX_READ_LOGPOINTS ? MAX_READ_LOGPOINTS : len;
-
- le_write32(payload, start_addr);
- le_write16(payload + 4, logpoints_len);
- payload[6] = 0x01;
-
- write_packet(PID_READ_DATALOG, payload, sizeof(payload));
- read_packet(PID_DATA, logpoints, logpoints_len, logpoints_len, false);
- write_packet(PID_ACK, nullptr, 0);
-
- for (unsigned char* p = logpoints; p < logpoints + logpoints_len; p += 32) {
- track_add_wpt(track, navilink_decode_logpoint(p));
- }
-
- len -= logpoints_len;
- start_addr += logpoints_len;
- }
-}
-
-static void
-serial_read_datalog()
-{
- unsigned int seg1_addr;
- unsigned int seg1_len;
- unsigned int seg2_addr;
- unsigned int seg2_len;
-
- read_datalog_info(&seg1_addr, &seg1_len, &seg2_addr, &seg2_len);
-
- auto* track = new route_head;
- track_add_head(track);
-
- if (seg1_len) {
- read_datalog_records(track, seg1_addr, seg1_len);
- }
-
- if (seg2_len) {
- read_datalog_records(track, seg2_addr, seg2_len);
- }
-}
-
-static void
-file_read()
-{
- unsigned char data[32];
- route_head* track = nullptr;
-
- while (gbfread(data, sizeof(data), 1, file_handle) == 1) {
- switch (le_read16(data)) {
- case 0x2000:
- fatal(MYNAME ": Route objects not supported in file sources\n");
- break;
- case 0x2010:
- fatal(MYNAME ": Subroute objects not supported in file sources\n");
- break;
- case 0x4000:
- if (global_opts.masked_objective & WPTDATAMASK) {
- waypt_add(decode_waypoint(data));
- }
- break;
- default:
- if (global_opts.masked_objective & TRKDATAMASK) {
- if (track == nullptr) {
- track = new route_head;
- track_add_head(track);
- }
-
- track_add_wpt(track, decode_trackpoint(data));
- }
- break;
- }
- }
-}
-
-static void
-file_write_waypoint(const Waypoint* waypt)
-{
- unsigned char data[32];
-
- encode_waypoint(waypt, data);
- gbfwrite(data, sizeof(data), 1, file_handle);
-}
-
-static void
-file_write_track_start(const route_head*)
-{
- track_serial = 1;
-}
-
-static void
-file_write_track_point(const Waypoint* waypt)
-{
- unsigned char data[32];
-
- encode_trackpoint(waypt, track_serial++, data);
- gbfwrite(data, sizeof(data), 1, file_handle);
-}
-
-static void
-file_write_track_end(const route_head*)
-{
-}
-
-static void
-file_write_route_start(const route_head*)
-{
- fatal(MYNAME ": Can't write routes to a file\n");
-}
-
-static void
-file_write_route_point(const Waypoint*)
-{
-}
-
-static void
-file_write_route_end(const route_head*)
-{
-}
-
-static void
-nuke()
-{
- if (nuketrk) {
- unsigned char information[32];
- unsigned char data[7];
-
- write_packet(PID_QRY_INFORMATION, nullptr, 0);
- read_packet(PID_DATA, information,
- sizeof(information), sizeof(information),
- false);
-
- le_write32(data + 0, le_read32(information + 4));
- le_write16(data + 4, 0);
- data[6] = 0;
-
- write_packet(PID_ERASE_TRACK, data, sizeof(data));
- read_packet(PID_CMD_OK, nullptr, 0, 0, false);
- }
-
- if (nukerte) {
- unsigned char data[4];
-
- le_write32(data, 0x00f00000);
- write_packet(PID_DEL_ALL_ROUTE, data, sizeof(data));
- if (!read_packet(PID_ACK, nullptr, 0, 0, true)) {
- fatal(MYNAME ": Could not nuke all routes.\n");
- }
- }
-
- if (nukewpt) {
- unsigned char data[4];
-
- le_write32(data, 0x00f00000);
- write_packet(PID_DEL_ALL_WAYPOINT, data, sizeof(data));
- if (!read_packet(PID_ACK, nullptr, 0, 0, true)) {
- fatal(MYNAME ": You must nuke all routes before nuking waypoints.\n");
- /* perhaps a better action would be to nuke routes for user.
- * i.e. set nukerte when nukewpt is set */
- }
- }
-
- if (nukedlg) {
- write_packet(PID_CLEAR_DATALOG, nullptr, 0);
- /* The flash erase operation is time-consuming. Each sector (64KB)
- * takes around 1 second. The total sectors for SBP is 10.
- * So give the device some time to clear its datalog, in addition
- * to SERIAL_TIMEOUT, which applies to read_packet() */
- QThread::usleep(CLEAR_DATALOG_TIME * 1000);
- read_packet(PID_ACK, nullptr, 0, 0, false);
- }
-}
-
-static void
-navilink_common_init(const QString& name)
-{
- if (gbser_is_serial(qPrintable(name))) {
- if ((serial_handle = gbser_init(qPrintable(name))) == nullptr) {
- fatal(MYNAME ": Could not open serial port %s\n", qPrintable(name));
- }
-
- if (gbser_set_port(serial_handle, 115200, 8, 0, 1) != gbser_OK) {
- fatal(MYNAME ": Can't configure port\n");
- }
-
- write_packet(PID_SYNC, nullptr, 0);
- read_packet(PID_ACK, nullptr, 0, 0, false);
-
- /* nuke data before writing */
- if (operation == WRITING) {
- nuke();
- }
-
- write_waypoint = serial_write_waypoint;
- write_track_start = serial_write_track_start;
- write_track_point = serial_write_track_point;
- write_track_end = serial_write_track_end;
- write_route_start = serial_write_route_start;
- write_route_point = serial_write_route_point;
- write_route_end = serial_write_route_end;
- } else {
- const char* mode = operation == READING ? "r" : "wb";
- file_handle = gbfopen(name, mode, MYNAME);
-
- write_waypoint = file_write_waypoint;
- write_track_start = file_write_track_start;
- write_track_point = file_write_track_point;
- write_track_end = file_write_track_end;
- write_route_start = file_write_route_start;
- write_route_point = file_write_route_point;
- write_route_end = file_write_route_end;
- }
-
-}
-
-static void
-navilink_rd_init(const QString& name)
-{
- operation = READING;
- navilink_common_init(name);
-}
-
-static void
-navilink_wr_init(const QString& name)
-{
- operation = WRITING;
- navilink_common_init(name);
-}
-
-static void
-navilink_deinit()
-{
- if (serial_handle) {
- /* nuke data after reading */
- if (operation == READING) {
- nuke();
- }
-
- if (poweroff) {
- write_packet(PID_QUIT, nullptr, 0);
- }
-
- gbser_deinit(serial_handle);
- }
-
- if (file_handle) {
- gbfclose(file_handle);
- }
-
-}
-
-static void
-navilink_read()
-{
- if (datalog) {
- if (global_opts.masked_objective & TRKDATAMASK) {
- if (serial_handle) {
- serial_read_datalog();
- } else if (file_handle) {
- fatal(MYNAME ": Not supported. Use SBP format.\n");
- }
- }
- } else {
- if (serial_handle) {
- Waypoint** waypts = nullptr;
-
- if (global_opts.masked_objective & (WPTDATAMASK|RTEDATAMASK)) {
- waypts = serial_read_waypoints();
- }
-
- if (global_opts.masked_objective & TRKDATAMASK) {
- serial_read_track();
- }
-
- if (global_opts.masked_objective & RTEDATAMASK) {
- serial_read_routes(waypts);
- }
-
- if (waypts) {
- free_waypoints(waypts);
- }
- } else if (file_handle) {
- file_read();
- }
- }
-}
-
-static void
-navilink_write()
-{
- if (datalog) {
- fatal(MYNAME ": Writing to datalog not supported.\n");
- }
-
- switch (global_opts.objective) {
- case trkdata:
- track_disp_all(write_track_start,
- write_track_end,
- write_track_point);
- break;
- case wptdata:
- waypt_disp_all(write_waypoint);
- break;
- case rtedata:
- if (serial_handle) {
- route_waypts = serial_read_waypoints();
- }
- route_disp_all(write_route_start,
- write_route_end,
- write_route_point);
- if (route_waypts) {
- free_waypoints(route_waypts);
- route_waypts = nullptr;
- }
- break;
- default:
- fatal(MYNAME ": Unknown objective.\n");
- }
-}
-
-ff_vecs_t navilink_vecs = {
- ff_type_serial,
- FF_CAP_RW_ALL,
- navilink_rd_init,
- navilink_wr_init,
- navilink_deinit,
- navilink_deinit,
- navilink_read,
- navilink_write,
- nullptr,
- &navilink_args,
- NULL_POS_OPS
-};
+++ /dev/null
-/*
- Locosys NaviGPS GT-31/BGT-31 common functions.
-
- Copyright (C) 2008 Rodney Lorrimar <rodney@rodney.id.au>
- Copyright (C) 2005 Robert Lipe, robertlipe@usa.net
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-
- */
-
-#ifndef NAVILINK_H_INCLUDED_
-#define NAVILINK_H_INCLUDED_
-
-#include <ctime>
-#include "defs.h"
-
-#define SBP_RECORD_LEN 32
-
-/* defined in navilink.c */
-Waypoint* navilink_decode_logpoint(const unsigned char* buffer);
-unsigned navilink_checksum_packet(const unsigned char* packet, unsigned length);
-
-/* defined in sbn.c */
-bool locosys_decode_file_id(char* header, size_t len);
-
-
-#ifdef THIS_IS_ONLY_FOR_REFERENCE
-/* Locosys SBP and SBN structures */
-
-typedef __packed struct {
- UINT8 HDOP; /* HDOP [0..51] with resolution 0.2 */
- UINT8 SVIDCnt; /* Number of SVs in solution [0 to 12] */
- UINT16 UtcSec; /* UTC Second [0 to 59] in seconds with resolution 0.001 */
- UINT32 date_time_UTC_packed; /* refer to protocol doc*/
- UINT32 SVIDList; /* SVs in solution: Bit 0=1: SV1, Bit 1=1: SV2, ... , Bit 31=1: SV32 */
- INT32 Lat; /* Latitude [-90 to 90] in degrees with resolution 0.0000001 */
- INT32 Lon; /* Longitude [-180 to 180] in degrees with resolution 0.0000001 */
- INT32 AltCM; /* Altitude from Mean Sea Level in centi meters */
- UINT16 Sog; /* Speed Over Ground in m/sec with resolution 0.01 */
- UINT16 Cog; /* Course Over Ground [0 to 360] in degrees with resolution 0.01 */
- INT16 ClmbRte; /* Climb rate in m/sec with resolution 0.01 */
- UINT8 bitFlags; /* bitFlags, default 0x00, bit 0=1 indicate the first point after power on */
- UINT8 reserved;
-} T_SBP;
-
-typedef struct __packed {
- UINT8 Mid;
- UINT16 Valid;
- UINT16 Mode; /* Nav Mode: bit map as follows:
- * Bits 2-0: GPS Fix Type
- * 000 = No Nav
- * 001 = 1 SV solution
- * 010 = 2 SV solution
- * 011 = 3 SV solution (2D)
- * 100 = 4 or more SV solution (3D)
- * 101 = Least Square 2D solution
- * 110 = Least Square 3D solution
- * 111 = DR solution (no SV)
- * Bit 3 : 1 = Trickle Power ON
- * Bits 5-4: Altitude Hold
- * 00 = No Altitude Hold
- * 01 = Altitude Hold using altitude from KF
- * 10 = Altitude Hold using altitude from user
- * 11 = forced altitude
- * Bit 6 : 1 = DOP exceeded
- * Bit 7 : 1 = DGPS correction applied
- * Bit 8 :
- * 1 = Sensor-based DR
- * 0 = Velocity DR, if bits 2-0 = 111
- * = see bits 15-14, if bits 2-0 != 111
- * Bit 9 : 1 = Solution validated
- * Bit 10 : 1 = Velocity DR Timeout
- * Bit 11 : 1 = Solution edited by UI
- * Bit 12 : 1 = Velocity invalid
- * Bit 13 : 1 = Altitude Hold disabled
- * Bits 15-14: SiRFDrive DR Status (applicable only when bit 8=0)
- * 00 = GPS Only
- * 01 = Calibrating
- * 10 = DR sensor error
- * 11 = DR Test mode
- */
- UINT16 Week; /* Extended Week Number */
- UINT32 TOW; /* Time of Week [0 to 604800] in seconds with resolution 0.001 */
- UINT16 UtcYr; /* UTC Year [1980 to 3000] */
- UINT8 UtcMth; /* UTC Month [1 to 12] */
- UINT8 UtcDay; /* UTC Day [1 to 31] */
- UINT8 UtcHr; /* UTC Hour [0 to 23] */
- UINT8 UtcMin; /* UTC Minute [0 to 59] */
- UINT16 UtcSec; /* UTC Second [0 to 59] in seconds with resolution 0.001 */
- UINT32 SVIDList; /* SVs in solution: Bit 0=1: SV1, Bit 1=1: SV2, ... , Bit 31=1: SV32 */
-
- INT32 Lat; /* Latitude [-90 to 90] in degrees with resolution 0.0000001 */
- INT32 Lon; /* Longitude [-180 to 180] in degrees with resolution 0.0000001 */
- INT32 AltE; /* Altitude from Ellipsoid in meters with resolution 0.01 */
- INT32 AltM; /* Altitude from Mean Sea Level in meters with resolution 0.01 */
- UINT8 Datum; /* Map datum */
- UINT16 Sog; /* Speed Over Ground in m/sec with resolution 0.01 */
- UINT16 Cog; /* Course Over Ground [0 to 360] in degrees with resolution 0.01 */
- INT16 MagVar; /* Magnetic Variation - Reserved */
- INT16 ClmbRte; /* Climb rate in m/sec with resolution 0.01 */
- INT16 HdRte; /* Heading Rate in deg/sec with resolution 0.01 (SiRFDrive only) */
- UINT32 Ehpe; /* Expected Horizontal Position Error in meters with resolution 0.01 */
- UINT32 Evpe; /* Expected Horizontal Vertical Error in meters with resolution 0.01 */
- UINT32 Ete; /* Expected Time Error in meters with resolution 0.01 (SiRFDrive only) - Reserved */
- UINT16 Ehve; /* Expected Horizontal Velocity Error in m/sec with resolution 0.01 (SiRFDrive only) */
- INT32 ClkBias; /* Clock Bias in meters with resolution 0.01 */
- UINT32 ClkBiasE; /* Clock Bias Error in meters with resolution 0.01 (SiRFDrive only) */
- INT32 ClkDrift; /* Clock Drift in m/sec with resolution 0.01 */
- UINT32 ClkDriftE; /* Clock Drift in m/sec with resolution 0.01 (SiRFDrive only) */
- UINT32 Trvled; /* Distance Traveled since reset in meters (SiRFDrive only) */
- UINT16 TrvledE; /* Distance Traveled Error in meters (SiRFDrive only) */
- UINT16 HdE; /* Heading Error [0 to 180] in degrees with resolution 0.01 (SiRFDrive only) */
- UINT8 SVIDCnt; /* Number of SVs in solution [0 to 12] */
- UINT8 HDOP; /* HDOP [0..51] with resolution 0.2 */
- UINT8 Reserved; /* Reserved */
-
- UINT16 ufSog; /* Speed Over Ground in m/sec with resolution 0.01 ,unfiltered*/
- UINT16 ufCog; /* Course Over Ground [0 to 360] in degrees with resolution 0.01, unfiltered */
-
-} T_SBN_REC;
-
-#endif
-
-#endif // NAVILINK_H_INCLUDED_
tpg tpg National Geographic Topo .tpg (waypoints)
tpo2 tpo National Geographic Topo 2.x .tpo
tpo3 tpo National Geographic Topo 3.x/4.x .tpo
-navilink NaviGPS GT-11/BGT-11 Download
-sbp sbp NaviGPS GT-31/BGT-31 datalogger (.sbp)
-sbn sbn NaviGPS GT-31/BGT-31 SiRF binary logfile (.sbn)
nmea NMEA 0183 sentences
osm osm OpenStreetMap data files
ozi OziExplorer
file tpg tpg National Geographic Topo .tpg (waypoints)
file tpo2 tpo National Geographic Topo 2.x .tpo
file tpo3 tpo National Geographic Topo 3.x/4.x .tpo
-serial navilink NaviGPS GT-11/BGT-11 Download
-file sbp sbp NaviGPS GT-31/BGT-31 datalogger (.sbp)
-file sbn sbn NaviGPS GT-31/BGT-31 SiRF binary logfile (.sbn)
file nmea NMEA 0183 sentences
file osm osm OpenStreetMap data files
file ozi OziExplorer
file rw---- tpg tpg National Geographic Topo .tpg (waypoints)
file --r--- tpo2 tpo National Geographic Topo 2.x .tpo
file r-r-r- tpo3 tpo National Geographic Topo 3.x/4.x .tpo
-serial rwrwrw navilink NaviGPS GT-11/BGT-11 Download
-file --r--- sbp sbp NaviGPS GT-31/BGT-31 datalogger (.sbp)
-file --r--- sbn sbn NaviGPS GT-31/BGT-31 SiRF binary logfile (.sbn)
file rwrw-- nmea NMEA 0183 sentences
file rw-wrw osm osm OpenStreetMap data files
file rwrwrw ozi OziExplorer
https://www.gpsbabel.org/WEB_DOC_DIR/fmt_tpo2.html
file r-r-r- tpo3 tpo National Geographic Topo 3.x/4.x .tpo tpo3
https://www.gpsbabel.org/WEB_DOC_DIR/fmt_tpo3.html
-serial rwrwrw navilink NaviGPS GT-11/BGT-11 Download navilink
- https://www.gpsbabel.org/WEB_DOC_DIR/fmt_navilink.html
-option navilink nuketrk Delete all track points boolean https://www.gpsbabel.org/WEB_DOC_DIR/fmt_navilink.html#fmt_navilink_o_nuketrk
-
-option navilink nukerte Delete all routes boolean https://www.gpsbabel.org/WEB_DOC_DIR/fmt_navilink.html#fmt_navilink_o_nukerte
-
-option navilink nukewpt Delete all waypoints boolean https://www.gpsbabel.org/WEB_DOC_DIR/fmt_navilink.html#fmt_navilink_o_nukewpt
-
-option navilink nukedlg Clear the datalog boolean https://www.gpsbabel.org/WEB_DOC_DIR/fmt_navilink.html#fmt_navilink_o_nukedlg
-
-option navilink datalog Read from datalogger buffer boolean https://www.gpsbabel.org/WEB_DOC_DIR/fmt_navilink.html#fmt_navilink_o_datalog
-
-option navilink power_off Command unit to power itself down boolean https://www.gpsbabel.org/WEB_DOC_DIR/fmt_navilink.html#fmt_navilink_o_power_off
-
-file --r--- sbp sbp NaviGPS GT-31/BGT-31 datalogger (.sbp) sbp
- https://www.gpsbabel.org/WEB_DOC_DIR/fmt_sbp.html
-file --r--- sbn sbn NaviGPS GT-31/BGT-31 SiRF binary logfile (.sbn) sbn
- https://www.gpsbabel.org/WEB_DOC_DIR/fmt_sbn.html
file rwrw-- nmea NMEA 0183 sentences nmea
https://www.gpsbabel.org/WEB_DOC_DIR/fmt_nmea.html
option nmea snlen Max length of waypoint name to write integer 6 1 64 https://www.gpsbabel.org/WEB_DOC_DIR/fmt_nmea.html#fmt_nmea_o_snlen
datum Datum (default=NAD27)
tpo2 National Geographic Topo 2.x .tpo
tpo3 National Geographic Topo 3.x/4.x .tpo
- navilink NaviGPS GT-11/BGT-11 Download
- nuketrk (0/1) Delete all track points
- nukerte (0/1) Delete all routes
- nukewpt (0/1) Delete all waypoints
- nukedlg (0/1) Clear the datalog
- datalog (0/1) Read from datalogger buffer
- power_off (0/1) Command unit to power itself down
- sbp NaviGPS GT-31/BGT-31 datalogger (.sbp)
- sbn NaviGPS GT-31/BGT-31 SiRF binary logfile (.sbn)
nmea NMEA 0183 sentences
snlen Max length of waypoint name to write
gprmc (0/1) Read/write GPRMC sentences
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<gpx version="1.0" creator="GPSBabel - https://www.gpsbabel.org" xmlns="http://www.topografix.com/GPX/1/0">
- <time>1970-01-01T00:00:00Z</time>
- <bounds minlat="51.758580000" minlon="-0.012070000" maxlat="51.764718300" maxlon="-0.003189900"/>
- <trk>
- <trkseg>
- <trkpt lat="51.758580000" lon="-0.012070000">
- <ele>0.000</ele>
- <time>2007-10-03T16:01:20Z</time>
- <course>0.000000</course>
- <speed>0.000000</speed>
- </trkpt>
- <trkpt lat="51.758580000" lon="-0.012070000">
- <ele>0.000</ele>
- <time>2007-10-03T16:01:22Z</time>
- <course>0.000000</course>
- <speed>0.000000</speed>
- </trkpt>
- <trkpt lat="51.758580000" lon="-0.012070000">
- <ele>0.000</ele>
- <time>2007-10-03T16:01:24Z</time>
- <course>0.000000</course>
- <speed>0.000000</speed>
- </trkpt>
- <trkpt lat="51.758580000" lon="-0.012033300">
- <ele>32.004</ele>
- <time>2007-10-03T16:01:46Z</time>
- <course>0.000000</course>
- <speed>0.000000</speed>
- </trkpt>
- <trkpt lat="51.758581600" lon="-0.012033300">
- <ele>32.918</ele>
- <time>2007-10-03T16:01:48Z</time>
- <course>0.000000</course>
- <speed>0.000000</speed>
- </trkpt>
- <trkpt lat="51.758581600" lon="-0.012033300">
- <ele>32.918</ele>
- <time>2007-10-03T16:01:50Z</time>
- <course>0.000000</course>
- <speed>0.000000</speed>
- </trkpt>
- <trkpt lat="51.758583300" lon="-0.012033300">
- <ele>37.490</ele>
- <time>2007-10-03T16:01:53Z</time>
- <course>0.000000</course>
- <speed>0.000000</speed>
- </trkpt>
- <trkpt lat="51.758583300" lon="-0.012031600">
- <ele>34.138</ele>
- <time>2007-10-03T16:01:55Z</time>
- <course>0.000000</course>
- <speed>0.000000</speed>
- </trkpt>
- <trkpt lat="51.758588300" lon="-0.012023300">
- <ele>33.223</ele>
- <time>2007-10-03T16:01:57Z</time>
- <course>23.000000</course>
- <speed>0.555556</speed>
- </trkpt>
- <trkpt lat="51.758603300" lon="-0.011998300">
- <ele>32.918</ele>
- <time>2007-10-03T16:01:59Z</time>
- <course>41.000000</course>
- <speed>1.111111</speed>
- </trkpt>
- <trkpt lat="51.758623300" lon="-0.011965000">
- <ele>32.614</ele>
- <time>2007-10-03T16:02:01Z</time>
- <course>47.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.758641600" lon="-0.011926600">
- <ele>32.309</ele>
- <time>2007-10-03T16:02:03Z</time>
- <course>57.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.758661600" lon="-0.011888300">
- <ele>32.614</ele>
- <time>2007-10-03T16:02:05Z</time>
- <course>47.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.758683300" lon="-0.011851600">
- <ele>32.614</ele>
- <time>2007-10-03T16:02:07Z</time>
- <course>57.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.758700000" lon="-0.011808300">
- <ele>32.918</ele>
- <time>2007-10-03T16:02:09Z</time>
- <course>63.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.758715000" lon="-0.011763300">
- <ele>33.528</ele>
- <time>2007-10-03T16:02:11Z</time>
- <course>61.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.758730000" lon="-0.011720000">
- <ele>33.833</ele>
- <time>2007-10-03T16:02:13Z</time>
- <course>63.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.758743300" lon="-0.011676600">
- <ele>34.138</ele>
- <time>2007-10-03T16:02:15Z</time>
- <course>63.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.758758300" lon="-0.011631600">
- <ele>34.747</ele>
- <time>2007-10-03T16:02:17Z</time>
- <course>64.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.758771600" lon="-0.011583300">
- <ele>35.052</ele>
- <time>2007-10-03T16:02:19Z</time>
- <course>69.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.758783300" lon="-0.011538300">
- <ele>35.357</ele>
- <time>2007-10-03T16:02:21Z</time>
- <course>71.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.758793300" lon="-0.011490000">
- <ele>35.966</ele>
- <time>2007-10-03T16:02:23Z</time>
- <course>71.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.758803300" lon="-0.011441600">
- <ele>36.576</ele>
- <time>2007-10-03T16:02:25Z</time>
- <course>78.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.758806600" lon="-0.011413300">
- <ele>36.576</ele>
- <time>2007-10-03T16:02:27Z</time>
- <course>76.000000</course>
- <speed>0.000000</speed>
- </trkpt>
- <trkpt lat="51.758821600" lon="-0.011333300">
- <ele>36.576</ele>
- <time>2007-10-03T16:02:29Z</time>
- <course>78.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.758828300" lon="-0.011276600">
- <ele>36.271</ele>
- <time>2007-10-03T16:02:31Z</time>
- <course>84.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.758835000" lon="-0.011213300">
- <ele>36.271</ele>
- <time>2007-10-03T16:02:33Z</time>
- <course>79.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.758841600" lon="-0.011158300">
- <ele>36.271</ele>
- <time>2007-10-03T16:02:35Z</time>
- <course>78.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.758845000" lon="-0.011108300">
- <ele>36.271</ele>
- <time>2007-10-03T16:02:37Z</time>
- <course>80.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.758848300" lon="-0.011070000">
- <ele>35.662</ele>
- <time>2007-10-03T16:02:39Z</time>
- <course>83.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.758851600" lon="-0.011028300">
- <ele>35.662</ele>
- <time>2007-10-03T16:02:41Z</time>
- <course>81.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.758860000" lon="-0.010986600">
- <ele>35.966</ele>
- <time>2007-10-03T16:02:43Z</time>
- <course>78.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.758865000" lon="-0.010944900">
- <ele>36.271</ele>
- <time>2007-10-03T16:02:45Z</time>
- <course>86.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.758866600" lon="-0.010921600">
- <ele>36.271</ele>
- <time>2007-10-03T16:02:47Z</time>
- <course>82.000000</course>
- <speed>0.000000</speed>
- </trkpt>
- <trkpt lat="51.758875000" lon="-0.010856600">
- <ele>36.881</ele>
- <time>2007-10-03T16:02:49Z</time>
- <course>80.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.758880000" lon="-0.010806600">
- <ele>36.881</ele>
- <time>2007-10-03T16:02:51Z</time>
- <course>82.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.758883300" lon="-0.010756600">
- <ele>37.186</ele>
- <time>2007-10-03T16:02:53Z</time>
- <course>82.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.758888300" lon="-0.010708300">
- <ele>37.490</ele>
- <time>2007-10-03T16:02:55Z</time>
- <course>82.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.758891600" lon="-0.010659900">
- <ele>37.186</ele>
- <time>2007-10-03T16:02:57Z</time>
- <course>84.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.758895000" lon="-0.010615000">
- <ele>37.186</ele>
- <time>2007-10-03T16:02:59Z</time>
- <course>84.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.758896600" lon="-0.010570000">
- <ele>37.186</ele>
- <time>2007-10-03T16:03:01Z</time>
- <course>84.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.758899900" lon="-0.010520000">
- <ele>37.186</ele>
- <time>2007-10-03T16:03:03Z</time>
- <course>83.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.758908300" lon="-0.010473300">
- <ele>38.405</ele>
- <time>2007-10-03T16:03:05Z</time>
- <course>84.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.758913300" lon="-0.010428300">
- <ele>38.405</ele>
- <time>2007-10-03T16:03:07Z</time>
- <course>86.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.758916600" lon="-0.010380000">
- <ele>38.405</ele>
- <time>2007-10-03T16:03:09Z</time>
- <course>86.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.758921600" lon="-0.010331600">
- <ele>38.405</ele>
- <time>2007-10-03T16:03:11Z</time>
- <course>84.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.758925000" lon="-0.010281600">
- <ele>38.405</ele>
- <time>2007-10-03T16:03:13Z</time>
- <course>84.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.758929900" lon="-0.010233300">
- <ele>38.405</ele>
- <time>2007-10-03T16:03:15Z</time>
- <course>83.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.758933300" lon="-0.010186600">
- <ele>38.405</ele>
- <time>2007-10-03T16:03:17Z</time>
- <course>81.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.758940000" lon="-0.010141600">
- <ele>38.100</ele>
- <time>2007-10-03T16:03:19Z</time>
- <course>85.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.758946600" lon="-0.010093300">
- <ele>38.100</ele>
- <time>2007-10-03T16:03:21Z</time>
- <course>85.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.758951600" lon="-0.010045000">
- <ele>38.100</ele>
- <time>2007-10-03T16:03:23Z</time>
- <course>78.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.758958300" lon="-0.009998300">
- <ele>38.100</ele>
- <time>2007-10-03T16:03:25Z</time>
- <course>82.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.758963300" lon="-0.009951600">
- <ele>37.795</ele>
- <time>2007-10-03T16:03:27Z</time>
- <course>79.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.758966600" lon="-0.009903300">
- <ele>37.490</ele>
- <time>2007-10-03T16:03:29Z</time>
- <course>80.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.758968300" lon="-0.009858300">
- <ele>37.186</ele>
- <time>2007-10-03T16:03:31Z</time>
- <course>84.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.758973300" lon="-0.009815000">
- <ele>36.881</ele>
- <time>2007-10-03T16:03:33Z</time>
- <course>75.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.758980000" lon="-0.009763300">
- <ele>36.881</ele>
- <time>2007-10-03T16:03:35Z</time>
- <course>79.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.758988300" lon="-0.009711600">
- <ele>37.186</ele>
- <time>2007-10-03T16:03:37Z</time>
- <course>78.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.758991600" lon="-0.009684900">
- <ele>37.186</ele>
- <time>2007-10-03T16:03:39Z</time>
- <course>86.000000</course>
- <speed>0.000000</speed>
- </trkpt>
- <trkpt lat="51.758991600" lon="-0.009684900">
- <ele>37.186</ele>
- <time>2007-10-03T16:03:41Z</time>
- <course>86.000000</course>
- <speed>0.000000</speed>
- </trkpt>
- <trkpt lat="51.758971600" lon="-0.009575000">
- <ele>35.966</ele>
- <time>2007-10-03T16:03:43Z</time>
- <course>94.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.758971600" lon="-0.009575000">
- <ele>35.966</ele>
- <time>2007-10-03T16:03:45Z</time>
- <course>94.000000</course>
- <speed>0.000000</speed>
- </trkpt>
- <trkpt lat="51.758971600" lon="-0.009575000">
- <ele>35.966</ele>
- <time>2007-10-03T16:03:47Z</time>
- <course>94.000000</course>
- <speed>0.000000</speed>
- </trkpt>
- <trkpt lat="51.759036600" lon="-0.009298300">
- <ele>35.052</ele>
- <time>2007-10-03T16:03:56Z</time>
- <course>57.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.759036600" lon="-0.009298300">
- <ele>35.052</ele>
- <time>2007-10-03T16:03:58Z</time>
- <course>57.000000</course>
- <speed>0.000000</speed>
- </trkpt>
- <trkpt lat="51.759070000" lon="-0.009225000">
- <ele>35.052</ele>
- <time>2007-10-03T16:04:00Z</time>
- <course>55.000000</course>
- <speed>1.111111</speed>
- </trkpt>
- <trkpt lat="51.759083300" lon="-0.009181600">
- <ele>35.966</ele>
- <time>2007-10-03T16:04:02Z</time>
- <course>68.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.759093300" lon="-0.009143300">
- <ele>35.966</ele>
- <time>2007-10-03T16:04:04Z</time>
- <course>59.000000</course>
- <speed>1.111111</speed>
- </trkpt>
- <trkpt lat="51.759108300" lon="-0.009113300">
- <ele>35.966</ele>
- <time>2007-10-03T16:04:06Z</time>
- <course>50.000000</course>
- <speed>1.111111</speed>
- </trkpt>
- <trkpt lat="51.759108300" lon="-0.009113300">
- <ele>35.966</ele>
- <time>2007-10-03T16:04:08Z</time>
- <course>50.000000</course>
- <speed>0.000000</speed>
- </trkpt>
- <trkpt lat="51.759133300" lon="-0.009025000">
- <ele>36.881</ele>
- <time>2007-10-03T16:04:10Z</time>
- <course>59.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.759146600" lon="-0.008981600">
- <ele>36.576</ele>
- <time>2007-10-03T16:04:12Z</time>
- <course>64.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.759156600" lon="-0.008935000">
- <ele>36.881</ele>
- <time>2007-10-03T16:04:14Z</time>
- <course>70.000000</course>
- <speed>1.111111</speed>
- </trkpt>
- <trkpt lat="51.759165000" lon="-0.008900000">
- <ele>37.186</ele>
- <time>2007-10-03T16:04:16Z</time>
- <course>68.000000</course>
- <speed>0.555556</speed>
- </trkpt>
- <trkpt lat="51.759176600" lon="-0.008868300">
- <ele>37.490</ele>
- <time>2007-10-03T16:04:18Z</time>
- <course>56.000000</course>
- <speed>1.111111</speed>
- </trkpt>
- <trkpt lat="51.759195000" lon="-0.008833300">
- <ele>37.186</ele>
- <time>2007-10-03T16:04:20Z</time>
- <course>51.000000</course>
- <speed>1.111111</speed>
- </trkpt>
- <trkpt lat="51.759213300" lon="-0.008791600">
- <ele>37.490</ele>
- <time>2007-10-03T16:04:22Z</time>
- <course>63.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.759228300" lon="-0.008743300">
- <ele>37.186</ele>
- <time>2007-10-03T16:04:24Z</time>
- <course>64.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.759235000" lon="-0.008716600">
- <ele>37.186</ele>
- <time>2007-10-03T16:04:26Z</time>
- <course>64.000000</course>
- <speed>0.000000</speed>
- </trkpt>
- <trkpt lat="51.759235000" lon="-0.008716600">
- <ele>37.186</ele>
- <time>2007-10-03T16:04:28Z</time>
- <course>64.000000</course>
- <speed>0.000000</speed>
- </trkpt>
- <trkpt lat="51.759293300" lon="-0.008516600">
- <ele>35.966</ele>
- <time>2007-10-03T16:04:42Z</time>
- <course>64.000000</course>
- <speed>0.000000</speed>
- </trkpt>
- <trkpt lat="51.759293300" lon="-0.008518300">
- <ele>35.662</ele>
- <time>2007-10-03T16:04:44Z</time>
- <course>64.000000</course>
- <speed>0.000000</speed>
- </trkpt>
- <trkpt lat="51.759301600" lon="-0.008520000">
- <ele>36.271</ele>
- <time>2007-10-03T16:04:46Z</time>
- <course>64.000000</course>
- <speed>0.000000</speed>
- </trkpt>
- <trkpt lat="51.759301600" lon="-0.008520000">
- <ele>36.271</ele>
- <time>2007-10-03T16:04:48Z</time>
- <course>64.000000</course>
- <speed>0.000000</speed>
- </trkpt>
- <trkpt lat="51.759311600" lon="-0.008510000">
- <ele>35.052</ele>
- <time>2007-10-03T16:04:51Z</time>
- <course>64.000000</course>
- <speed>0.000000</speed>
- </trkpt>
- <trkpt lat="51.759353300" lon="-0.008471600">
- <ele>36.576</ele>
- <time>2007-10-03T16:04:53Z</time>
- <course>57.000000</course>
- <speed>1.111111</speed>
- </trkpt>
- <trkpt lat="51.759370000" lon="-0.008436600">
- <ele>36.881</ele>
- <time>2007-10-03T16:04:55Z</time>
- <course>53.000000</course>
- <speed>1.111111</speed>
- </trkpt>
- <trkpt lat="51.759385000" lon="-0.008400000">
- <ele>36.576</ele>
- <time>2007-10-03T16:04:57Z</time>
- <course>57.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.759403300" lon="-0.008360000">
- <ele>36.576</ele>
- <time>2007-10-03T16:04:59Z</time>
- <course>53.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.759421600" lon="-0.008323300">
- <ele>36.576</ele>
- <time>2007-10-03T16:05:01Z</time>
- <course>52.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.759438300" lon="-0.008288300">
- <ele>36.576</ele>
- <time>2007-10-03T16:05:03Z</time>
- <course>50.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.759456600" lon="-0.008256600">
- <ele>36.881</ele>
- <time>2007-10-03T16:05:05Z</time>
- <course>50.000000</course>
- <speed>1.111111</speed>
- </trkpt>
- <trkpt lat="51.759473300" lon="-0.008225000">
- <ele>37.186</ele>
- <time>2007-10-03T16:05:07Z</time>
- <course>48.000000</course>
- <speed>1.111111</speed>
- </trkpt>
- <trkpt lat="51.759490000" lon="-0.008195000">
- <ele>37.490</ele>
- <time>2007-10-03T16:05:09Z</time>
- <course>50.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.759508300" lon="-0.008160000">
- <ele>37.795</ele>
- <time>2007-10-03T16:05:11Z</time>
- <course>45.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.759528300" lon="-0.008126600">
- <ele>37.490</ele>
- <time>2007-10-03T16:05:13Z</time>
- <course>46.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.759546600" lon="-0.008091600">
- <ele>36.881</ele>
- <time>2007-10-03T16:05:15Z</time>
- <course>47.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.759555000" lon="-0.008073300">
- <ele>36.576</ele>
- <time>2007-10-03T16:05:17Z</time>
- <course>56.000000</course>
- <speed>0.000000</speed>
- </trkpt>
- <trkpt lat="51.759565000" lon="-0.008035000">
- <ele>35.357</ele>
- <time>2007-10-03T16:05:19Z</time>
- <course>56.000000</course>
- <speed>0.000000</speed>
- </trkpt>
- <trkpt lat="51.759565000" lon="-0.008035000">
- <ele>35.357</ele>
- <time>2007-10-03T16:05:21Z</time>
- <course>56.000000</course>
- <speed>0.000000</speed>
- </trkpt>
- <trkpt lat="51.759573300" lon="-0.008025000">
- <ele>35.662</ele>
- <time>2007-10-03T16:05:23Z</time>
- <course>107.000000</course>
- <speed>0.555556</speed>
- </trkpt>
- <trkpt lat="51.759561600" lon="-0.008011600">
- <ele>35.966</ele>
- <time>2007-10-03T16:05:25Z</time>
- <course>126.000000</course>
- <speed>1.111111</speed>
- </trkpt>
- <trkpt lat="51.759556600" lon="-0.007985000">
- <ele>35.966</ele>
- <time>2007-10-03T16:05:27Z</time>
- <course>103.000000</course>
- <speed>1.111111</speed>
- </trkpt>
- <trkpt lat="51.759544900" lon="-0.007928300">
- <ele>34.747</ele>
- <time>2007-10-03T16:05:30Z</time>
- <course>104.000000</course>
- <speed>1.111111</speed>
- </trkpt>
- <trkpt lat="51.759546600" lon="-0.007891600">
- <ele>34.442</ele>
- <time>2007-10-03T16:05:32Z</time>
- <course>81.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.759565000" lon="-0.007861600">
- <ele>33.833</ele>
- <time>2007-10-03T16:05:34Z</time>
- <course>18.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.759591600" lon="-0.007848300">
- <ele>33.528</ele>
- <time>2007-10-03T16:05:36Z</time>
- <course>23.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.759623300" lon="-0.007840000">
- <ele>32.918</ele>
- <time>2007-10-03T16:05:38Z</time>
- <course>20.000000</course>
- <speed>1.111111</speed>
- </trkpt>
- <trkpt lat="51.759623300" lon="-0.007840000">
- <ele>32.918</ele>
- <time>2007-10-03T16:05:40Z</time>
- <course>20.000000</course>
- <speed>0.000000</speed>
- </trkpt>
- <trkpt lat="51.759623300" lon="-0.007840000">
- <ele>32.918</ele>
- <time>2007-10-03T16:05:42Z</time>
- <course>20.000000</course>
- <speed>0.000000</speed>
- </trkpt>
- <trkpt lat="51.759683300" lon="-0.007813300">
- <ele>32.004</ele>
- <time>2007-10-03T16:05:43Z</time>
- <course>18.000000</course>
- <speed>1.111111</speed>
- </trkpt>
- <trkpt lat="51.759683300" lon="-0.007813300">
- <ele>32.004</ele>
- <time>2007-10-03T16:05:46Z</time>
- <course>18.000000</course>
- <speed>0.000000</speed>
- </trkpt>
- <trkpt lat="51.759786600" lon="-0.007696600">
- <ele>31.699</ele>
- <time>2007-10-03T16:05:55Z</time>
- <course>18.000000</course>
- <speed>0.000000</speed>
- </trkpt>
- <trkpt lat="51.759795000" lon="-0.007680000">
- <ele>31.699</ele>
- <time>2007-10-03T16:05:57Z</time>
- <course>18.000000</course>
- <speed>0.000000</speed>
- </trkpt>
- <trkpt lat="51.759795000" lon="-0.007680000">
- <ele>31.699</ele>
- <time>2007-10-03T16:05:59Z</time>
- <course>18.000000</course>
- <speed>0.000000</speed>
- </trkpt>
- <trkpt lat="51.759880000" lon="-0.007583300">
- <ele>31.394</ele>
- <time>2007-10-03T16:06:05Z</time>
- <course>18.000000</course>
- <speed>0.000000</speed>
- </trkpt>
- <trkpt lat="51.759906600" lon="-0.007560000">
- <ele>31.699</ele>
- <time>2007-10-03T16:06:07Z</time>
- <course>18.000000</course>
- <speed>0.000000</speed>
- </trkpt>
- <trkpt lat="51.759906600" lon="-0.007560000">
- <ele>31.699</ele>
- <time>2007-10-03T16:06:09Z</time>
- <course>18.000000</course>
- <speed>0.000000</speed>
- </trkpt>
- <trkpt lat="51.759906600" lon="-0.007560000">
- <ele>31.699</ele>
- <time>2007-10-03T16:06:11Z</time>
- <course>18.000000</course>
- <speed>0.000000</speed>
- </trkpt>
- <trkpt lat="51.760084900" lon="-0.007390000">
- <ele>31.394</ele>
- <time>2007-10-03T16:06:22Z</time>
- <course>18.000000</course>
- <speed>0.000000</speed>
- </trkpt>
- <trkpt lat="51.760084900" lon="-0.007390000">
- <ele>31.394</ele>
- <time>2007-10-03T16:06:24Z</time>
- <course>18.000000</course>
- <speed>0.000000</speed>
- </trkpt>
- <trkpt lat="51.760084900" lon="-0.007390000">
- <ele>31.394</ele>
- <time>2007-10-03T16:06:26Z</time>
- <course>18.000000</course>
- <speed>0.000000</speed>
- </trkpt>
- <trkpt lat="51.760136600" lon="-0.007323300">
- <ele>31.699</ele>
- <time>2007-10-03T16:06:28Z</time>
- <course>18.000000</course>
- <speed>0.000000</speed>
- </trkpt>
- <trkpt lat="51.760156600" lon="-0.007321600">
- <ele>31.699</ele>
- <time>2007-10-03T16:06:30Z</time>
- <course>18.000000</course>
- <speed>0.000000</speed>
- </trkpt>
- <trkpt lat="51.760156600" lon="-0.007321600">
- <ele>31.699</ele>
- <time>2007-10-03T16:06:32Z</time>
- <course>18.000000</course>
- <speed>0.000000</speed>
- </trkpt>
- <trkpt lat="51.760156600" lon="-0.007321600">
- <ele>31.699</ele>
- <time>2007-10-03T16:06:34Z</time>
- <course>18.000000</course>
- <speed>0.000000</speed>
- </trkpt>
- <trkpt lat="51.760598300" lon="-0.007103300">
- <ele>29.566</ele>
- <time>2007-10-03T16:07:08Z</time>
- <course>18.000000</course>
- <speed>0.000000</speed>
- </trkpt>
- <trkpt lat="51.760690000" lon="-0.007025000">
- <ele>33.223</ele>
- <time>2007-10-03T16:07:10Z</time>
- <course>15.000000</course>
- <speed>1.111111</speed>
- </trkpt>
- <trkpt lat="51.760678300" lon="-0.007036600">
- <ele>32.309</ele>
- <time>2007-10-03T16:07:12Z</time>
- <course>16.000000</course>
- <speed>1.111111</speed>
- </trkpt>
- <trkpt lat="51.760678300" lon="-0.007036600">
- <ele>32.309</ele>
- <time>2007-10-03T16:07:14Z</time>
- <course>16.000000</course>
- <speed>0.000000</speed>
- </trkpt>
- <trkpt lat="51.760678300" lon="-0.007036600">
- <ele>32.309</ele>
- <time>2007-10-03T16:07:16Z</time>
- <course>16.000000</course>
- <speed>0.000000</speed>
- </trkpt>
- <trkpt lat="51.760773300" lon="-0.007003300">
- <ele>34.442</ele>
- <time>2007-10-03T16:07:18Z</time>
- <course>17.000000</course>
- <speed>1.111111</speed>
- </trkpt>
- <trkpt lat="51.760800000" lon="-0.006995000">
- <ele>34.747</ele>
- <time>2007-10-03T16:07:20Z</time>
- <course>14.000000</course>
- <speed>1.111111</speed>
- </trkpt>
- <trkpt lat="51.760825000" lon="-0.006983300">
- <ele>35.052</ele>
- <time>2007-10-03T16:07:22Z</time>
- <course>16.000000</course>
- <speed>1.111111</speed>
- </trkpt>
- <trkpt lat="51.760836600" lon="-0.006976600">
- <ele>34.747</ele>
- <time>2007-10-03T16:07:24Z</time>
- <course>18.000000</course>
- <speed>0.000000</speed>
- </trkpt>
- <trkpt lat="51.760836600" lon="-0.006976600">
- <ele>34.747</ele>
- <time>2007-10-03T16:07:26Z</time>
- <course>18.000000</course>
- <speed>0.000000</speed>
- </trkpt>
- <trkpt lat="51.760961600" lon="-0.006853300">
- <ele>32.918</ele>
- <time>2007-10-03T16:07:34Z</time>
- <course>38.000000</course>
- <speed>1.111111</speed>
- </trkpt>
- <trkpt lat="51.760970000" lon="-0.006816600">
- <ele>32.918</ele>
- <time>2007-10-03T16:07:36Z</time>
- <course>61.000000</course>
- <speed>1.111111</speed>
- </trkpt>
- <trkpt lat="51.760978300" lon="-0.006780000">
- <ele>32.309</ele>
- <time>2007-10-03T16:07:38Z</time>
- <course>62.000000</course>
- <speed>1.111111</speed>
- </trkpt>
- <trkpt lat="51.760989900" lon="-0.006756600">
- <ele>32.004</ele>
- <time>2007-10-03T16:07:40Z</time>
- <course>40.000000</course>
- <speed>0.555556</speed>
- </trkpt>
- <trkpt lat="51.761019900" lon="-0.006718300">
- <ele>37.490</ele>
- <time>2007-10-03T16:08:28Z</time>
- <course>0.000000</course>
- <speed>0.000000</speed>
- </trkpt>
- <trkpt lat="51.761021600" lon="-0.006713300">
- <ele>38.710</ele>
- <time>2007-10-03T16:08:29Z</time>
- <course>0.000000</course>
- <speed>0.000000</speed>
- </trkpt>
- <trkpt lat="51.761031600" lon="-0.006715000">
- <ele>39.929</ele>
- <time>2007-10-03T16:08:32Z</time>
- <course>0.000000</course>
- <speed>0.000000</speed>
- </trkpt>
- <trkpt lat="51.761031600" lon="-0.006713300">
- <ele>39.319</ele>
- <time>2007-10-03T16:08:33Z</time>
- <course>0.000000</course>
- <speed>0.000000</speed>
- </trkpt>
- <trkpt lat="51.761038300" lon="-0.006716600">
- <ele>37.490</ele>
- <time>2007-10-03T16:08:36Z</time>
- <course>0.000000</course>
- <speed>0.000000</speed>
- </trkpt>
- <trkpt lat="51.761038300" lon="-0.006715000">
- <ele>38.100</ele>
- <time>2007-10-03T16:08:37Z</time>
- <course>0.000000</course>
- <speed>0.000000</speed>
- </trkpt>
- <trkpt lat="51.761038300" lon="-0.006705000">
- <ele>41.148</ele>
- <time>2007-10-03T16:08:40Z</time>
- <course>0.000000</course>
- <speed>0.000000</speed>
- </trkpt>
- <trkpt lat="51.761038300" lon="-0.006703300">
- <ele>42.062</ele>
- <time>2007-10-03T16:08:41Z</time>
- <course>0.000000</course>
- <speed>0.000000</speed>
- </trkpt>
- <trkpt lat="51.761036600" lon="-0.006701600">
- <ele>43.586</ele>
- <time>2007-10-03T16:08:43Z</time>
- <course>0.000000</course>
- <speed>0.000000</speed>
- </trkpt>
- <trkpt lat="51.761033300" lon="-0.006710000">
- <ele>45.110</ele>
- <time>2007-10-03T16:08:46Z</time>
- <course>0.000000</course>
- <speed>0.000000</speed>
- </trkpt>
- <trkpt lat="51.761030000" lon="-0.006715000">
- <ele>45.110</ele>
- <time>2007-10-03T16:08:47Z</time>
- <course>0.000000</course>
- <speed>0.000000</speed>
- </trkpt>
- <trkpt lat="51.761023300" lon="-0.006730000">
- <ele>45.110</ele>
- <time>2007-10-03T16:08:50Z</time>
- <course>0.000000</course>
- <speed>0.000000</speed>
- </trkpt>
- <trkpt lat="51.761021600" lon="-0.006735000">
- <ele>44.806</ele>
- <time>2007-10-03T16:08:51Z</time>
- <course>0.000000</course>
- <speed>0.000000</speed>
- </trkpt>
- <trkpt lat="51.761019900" lon="-0.006745000">
- <ele>43.586</ele>
- <time>2007-10-03T16:08:54Z</time>
- <course>0.000000</course>
- <speed>0.000000</speed>
- </trkpt>
- <trkpt lat="51.761018300" lon="-0.006746600">
- <ele>42.977</ele>
- <time>2007-10-03T16:08:55Z</time>
- <course>0.000000</course>
- <speed>0.000000</speed>
- </trkpt>
- <trkpt lat="51.761026600" lon="-0.006726600">
- <ele>42.062</ele>
- <time>2007-10-03T16:08:58Z</time>
- <course>35.000000</course>
- <speed>1.111111</speed>
- </trkpt>
- <trkpt lat="51.761040000" lon="-0.006715000">
- <ele>42.367</ele>
- <time>2007-10-03T16:08:59Z</time>
- <course>28.000000</course>
- <speed>1.111111</speed>
- </trkpt>
- <trkpt lat="51.761085000" lon="-0.006695000">
- <ele>42.672</ele>
- <time>2007-10-03T16:09:02Z</time>
- <course>16.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.761100000" lon="-0.006695000">
- <ele>42.367</ele>
- <time>2007-10-03T16:09:03Z</time>
- <course>17.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.761145000" lon="-0.006681600">
- <ele>41.453</ele>
- <time>2007-10-03T16:09:06Z</time>
- <course>21.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.761161600" lon="-0.006670000">
- <ele>41.758</ele>
- <time>2007-10-03T16:09:07Z</time>
- <course>22.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.761205000" lon="-0.006635000">
- <ele>41.758</ele>
- <time>2007-10-03T16:09:10Z</time>
- <course>29.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.761216600" lon="-0.006623300">
- <ele>41.453</ele>
- <time>2007-10-03T16:09:11Z</time>
- <course>34.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.761229900" lon="-0.006610000">
- <ele>41.148</ele>
- <time>2007-10-03T16:09:13Z</time>
- <course>36.000000</course>
- <speed>0.000000</speed>
- </trkpt>
- <trkpt lat="51.761288300" lon="-0.006538300">
- <ele>40.843</ele>
- <time>2007-10-03T16:09:16Z</time>
- <course>65.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.761295000" lon="-0.006515000">
- <ele>41.148</ele>
- <time>2007-10-03T16:09:17Z</time>
- <course>65.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.761311600" lon="-0.006446600">
- <ele>40.843</ele>
- <time>2007-10-03T16:09:20Z</time>
- <course>68.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.761316600" lon="-0.006425000">
- <ele>40.843</ele>
- <time>2007-10-03T16:09:21Z</time>
- <course>71.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.761326600" lon="-0.006354900">
- <ele>40.843</ele>
- <time>2007-10-03T16:09:24Z</time>
- <course>78.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.761330000" lon="-0.006330000">
- <ele>41.148</ele>
- <time>2007-10-03T16:09:25Z</time>
- <course>80.000000</course>
- <speed>1.111111</speed>
- </trkpt>
- <trkpt lat="51.761336600" lon="-0.006258300">
- <ele>41.453</ele>
- <time>2007-10-03T16:09:28Z</time>
- <course>82.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.761338300" lon="-0.006233300">
- <ele>41.453</ele>
- <time>2007-10-03T16:09:29Z</time>
- <course>85.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.761353300" lon="-0.006171600">
- <ele>41.148</ele>
- <time>2007-10-03T16:09:32Z</time>
- <course>53.000000</course>
- <speed>1.111111</speed>
- </trkpt>
- <trkpt lat="51.761363300" lon="-0.006156600">
- <ele>41.148</ele>
- <time>2007-10-03T16:09:33Z</time>
- <course>37.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.761403300" lon="-0.006141600">
- <ele>40.538</ele>
- <time>2007-10-03T16:09:36Z</time>
- <course>5.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.761418300" lon="-0.006140000">
- <ele>40.538</ele>
- <time>2007-10-03T16:09:37Z</time>
- <course>4.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.761454900" lon="-0.006153300">
- <ele>41.453</ele>
- <time>2007-10-03T16:09:40Z</time>
- <course>288.000000</course>
- <speed>1.111111</speed>
- </trkpt>
- <trkpt lat="51.761461600" lon="-0.006169900">
- <ele>41.453</ele>
- <time>2007-10-03T16:09:41Z</time>
- <course>290.000000</course>
- <speed>1.111111</speed>
- </trkpt>
- <trkpt lat="51.761465000" lon="-0.006216600">
- <ele>41.758</ele>
- <time>2007-10-03T16:09:44Z</time>
- <course>279.000000</course>
- <speed>0.000000</speed>
- </trkpt>
- <trkpt lat="51.761463300" lon="-0.006218300">
- <ele>42.062</ele>
- <time>2007-10-03T16:09:46Z</time>
- <course>279.000000</course>
- <speed>0.000000</speed>
- </trkpt>
- <trkpt lat="51.761465000" lon="-0.006221600">
- <ele>42.367</ele>
- <time>2007-10-03T16:09:47Z</time>
- <course>295.000000</course>
- <speed>0.555556</speed>
- </trkpt>
- <trkpt lat="51.761481600" lon="-0.006266600">
- <ele>42.672</ele>
- <time>2007-10-03T16:09:50Z</time>
- <course>299.000000</course>
- <speed>1.111111</speed>
- </trkpt>
- <trkpt lat="51.761486600" lon="-0.006286600">
- <ele>42.672</ele>
- <time>2007-10-03T16:09:51Z</time>
- <course>300.000000</course>
- <speed>1.111111</speed>
- </trkpt>
- <trkpt lat="51.761510000" lon="-0.006341600">
- <ele>43.282</ele>
- <time>2007-10-03T16:09:54Z</time>
- <course>308.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.761518300" lon="-0.006360000">
- <ele>43.282</ele>
- <time>2007-10-03T16:09:55Z</time>
- <course>308.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.761543300" lon="-0.006410000">
- <ele>43.586</ele>
- <time>2007-10-03T16:09:58Z</time>
- <course>316.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.761555000" lon="-0.006423300">
- <ele>43.586</ele>
- <time>2007-10-03T16:09:59Z</time>
- <course>323.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.761591600" lon="-0.006461600">
- <ele>43.282</ele>
- <time>2007-10-03T16:10:02Z</time>
- <course>327.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.761603300" lon="-0.006475000">
- <ele>43.282</ele>
- <time>2007-10-03T16:10:03Z</time>
- <course>320.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.761638300" lon="-0.006516600">
- <ele>43.586</ele>
- <time>2007-10-03T16:10:06Z</time>
- <course>327.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.761651600" lon="-0.006530000">
- <ele>43.586</ele>
- <time>2007-10-03T16:10:07Z</time>
- <course>331.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.761688300" lon="-0.006571600">
- <ele>43.891</ele>
- <time>2007-10-03T16:10:10Z</time>
- <course>324.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.761700000" lon="-0.006585000">
- <ele>44.196</ele>
- <time>2007-10-03T16:10:11Z</time>
- <course>327.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.761738300" lon="-0.006613300">
- <ele>44.501</ele>
- <time>2007-10-03T16:10:14Z</time>
- <course>342.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.761765000" lon="-0.006623300">
- <ele>44.196</ele>
- <time>2007-10-03T16:10:16Z</time>
- <course>353.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.761780000" lon="-0.006621600">
- <ele>44.196</ele>
- <time>2007-10-03T16:10:17Z</time>
- <course>3.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.761823300" lon="-0.006608300">
- <ele>43.282</ele>
- <time>2007-10-03T16:10:20Z</time>
- <course>15.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.761836600" lon="-0.006600000">
- <ele>42.672</ele>
- <time>2007-10-03T16:10:21Z</time>
- <course>19.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.761878300" lon="-0.006576600">
- <ele>42.062</ele>
- <time>2007-10-03T16:10:24Z</time>
- <course>20.000000</course>
- <speed>1.111111</speed>
- </trkpt>
- <trkpt lat="51.761891600" lon="-0.006570000">
- <ele>42.062</ele>
- <time>2007-10-03T16:10:25Z</time>
- <course>20.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.761913300" lon="-0.006555000">
- <ele>41.758</ele>
- <time>2007-10-03T16:10:28Z</time>
- <course>25.000000</course>
- <speed>0.000000</speed>
- </trkpt>
- <trkpt lat="51.761936600" lon="-0.006541600">
- <ele>41.758</ele>
- <time>2007-10-03T16:10:29Z</time>
- <course>26.000000</course>
- <speed>1.111111</speed>
- </trkpt>
- <trkpt lat="51.761971600" lon="-0.006508300">
- <ele>42.062</ele>
- <time>2007-10-03T16:10:32Z</time>
- <course>26.000000</course>
- <speed>1.111111</speed>
- </trkpt>
- <trkpt lat="51.761983300" lon="-0.006496600">
- <ele>42.367</ele>
- <time>2007-10-03T16:10:33Z</time>
- <course>29.000000</course>
- <speed>1.111111</speed>
- </trkpt>
- <trkpt lat="51.762020000" lon="-0.006470000">
- <ele>42.062</ele>
- <time>2007-10-03T16:10:36Z</time>
- <course>23.000000</course>
- <speed>1.111111</speed>
- </trkpt>
- <trkpt lat="51.762033300" lon="-0.006460000">
- <ele>42.367</ele>
- <time>2007-10-03T16:10:37Z</time>
- <course>22.000000</course>
- <speed>1.111111</speed>
- </trkpt>
- <trkpt lat="51.762058300" lon="-0.006445000">
- <ele>42.062</ele>
- <time>2007-10-03T16:10:39Z</time>
- <course>22.000000</course>
- <speed>1.111111</speed>
- </trkpt>
- <trkpt lat="51.762080000" lon="-0.006429900">
- <ele>41.148</ele>
- <time>2007-10-03T16:10:41Z</time>
- <course>29.000000</course>
- <speed>1.111111</speed>
- </trkpt>
- <trkpt lat="51.762110000" lon="-0.006400000">
- <ele>40.234</ele>
- <time>2007-10-03T16:10:44Z</time>
- <course>29.000000</course>
- <speed>1.111111</speed>
- </trkpt>
- <trkpt lat="51.762123300" lon="-0.006390000">
- <ele>40.234</ele>
- <time>2007-10-03T16:10:45Z</time>
- <course>29.000000</course>
- <speed>1.111111</speed>
- </trkpt>
- <trkpt lat="51.762151600" lon="-0.006373300">
- <ele>40.234</ele>
- <time>2007-10-03T16:10:47Z</time>
- <course>21.000000</course>
- <speed>1.111111</speed>
- </trkpt>
- <trkpt lat="51.762193300" lon="-0.006348300">
- <ele>40.538</ele>
- <time>2007-10-03T16:10:50Z</time>
- <course>23.000000</course>
- <speed>1.111111</speed>
- </trkpt>
- <trkpt lat="51.762206600" lon="-0.006338300">
- <ele>40.843</ele>
- <time>2007-10-03T16:10:51Z</time>
- <course>23.000000</course>
- <speed>1.111111</speed>
- </trkpt>
- <trkpt lat="51.762249900" lon="-0.006310000">
- <ele>41.453</ele>
- <time>2007-10-03T16:10:54Z</time>
- <course>27.000000</course>
- <speed>1.111111</speed>
- </trkpt>
- <trkpt lat="51.762261600" lon="-0.006300000">
- <ele>40.843</ele>
- <time>2007-10-03T16:10:55Z</time>
- <course>27.000000</course>
- <speed>1.111111</speed>
- </trkpt>
- <trkpt lat="51.762296600" lon="-0.006268300">
- <ele>39.319</ele>
- <time>2007-10-03T16:10:58Z</time>
- <course>30.000000</course>
- <speed>1.111111</speed>
- </trkpt>
- <trkpt lat="51.762308300" lon="-0.006258300">
- <ele>38.710</ele>
- <time>2007-10-03T16:10:59Z</time>
- <course>31.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.762346600" lon="-0.006216600">
- <ele>38.100</ele>
- <time>2007-10-03T16:11:02Z</time>
- <course>40.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.762356600" lon="-0.006200000">
- <ele>37.795</ele>
- <time>2007-10-03T16:11:03Z</time>
- <course>45.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.762381600" lon="-0.006141600">
- <ele>36.881</ele>
- <time>2007-10-03T16:11:06Z</time>
- <course>64.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.762388300" lon="-0.006120000">
- <ele>36.881</ele>
- <time>2007-10-03T16:11:07Z</time>
- <course>73.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.762403300" lon="-0.006045000">
- <ele>37.795</ele>
- <time>2007-10-03T16:11:10Z</time>
- <course>77.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.762408300" lon="-0.006016600">
- <ele>38.100</ele>
- <time>2007-10-03T16:11:11Z</time>
- <course>77.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.762423300" lon="-0.005935000">
- <ele>38.710</ele>
- <time>2007-10-03T16:11:14Z</time>
- <course>74.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.762431600" lon="-0.005888300">
- <ele>37.490</ele>
- <time>2007-10-03T16:11:16Z</time>
- <course>69.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.762436600" lon="-0.005865000">
- <ele>37.186</ele>
- <time>2007-10-03T16:11:17Z</time>
- <course>69.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.762455000" lon="-0.005801600">
- <ele>36.576</ele>
- <time>2007-10-03T16:11:20Z</time>
- <course>56.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.762463300" lon="-0.005783300">
- <ele>36.271</ele>
- <time>2007-10-03T16:11:21Z</time>
- <course>58.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.762486600" lon="-0.005726600">
- <ele>35.966</ele>
- <time>2007-10-03T16:11:24Z</time>
- <course>48.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.762496600" lon="-0.005710000">
- <ele>35.966</ele>
- <time>2007-10-03T16:11:25Z</time>
- <course>49.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.762528300" lon="-0.005671600">
- <ele>35.357</ele>
- <time>2007-10-03T16:11:28Z</time>
- <course>32.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.762540000" lon="-0.005661600">
- <ele>35.052</ele>
- <time>2007-10-03T16:11:29Z</time>
- <course>34.000000</course>
- <speed>1.111111</speed>
- </trkpt>
- <trkpt lat="51.762578300" lon="-0.005633300">
- <ele>35.357</ele>
- <time>2007-10-03T16:11:32Z</time>
- <course>24.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.762593300" lon="-0.005626600">
- <ele>35.052</ele>
- <time>2007-10-03T16:11:33Z</time>
- <course>20.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.762621600" lon="-0.005615000">
- <ele>34.747</ele>
- <time>2007-10-03T16:11:35Z</time>
- <course>17.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.762653300" lon="-0.005601600">
- <ele>35.357</ele>
- <time>2007-10-03T16:11:37Z</time>
- <course>13.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.762703300" lon="-0.005595000">
- <ele>36.271</ele>
- <time>2007-10-03T16:11:40Z</time>
- <course>359.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.762720000" lon="-0.005593300">
- <ele>36.576</ele>
- <time>2007-10-03T16:11:41Z</time>
- <course>1.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.762768300" lon="-0.005595000">
- <ele>37.795</ele>
- <time>2007-10-03T16:11:44Z</time>
- <course>357.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.762800000" lon="-0.005601600">
- <ele>38.405</ele>
- <time>2007-10-03T16:11:46Z</time>
- <course>353.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.762815000" lon="-0.005605000">
- <ele>38.405</ele>
- <time>2007-10-03T16:11:47Z</time>
- <course>353.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.762861600" lon="-0.005611600">
- <ele>38.100</ele>
- <time>2007-10-03T16:11:50Z</time>
- <course>0.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.762876600" lon="-0.005608300">
- <ele>38.100</ele>
- <time>2007-10-03T16:11:51Z</time>
- <course>10.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.762918300" lon="-0.005603300">
- <ele>37.795</ele>
- <time>2007-10-03T16:11:54Z</time>
- <course>92.000000</course>
- <speed>1.111111</speed>
- </trkpt>
- <trkpt lat="51.762931600" lon="-0.005603300">
- <ele>37.795</ele>
- <time>2007-10-03T16:11:55Z</time>
- <course>46.000000</course>
- <speed>1.111111</speed>
- </trkpt>
- <trkpt lat="51.762953300" lon="-0.005605000">
- <ele>38.405</ele>
- <time>2007-10-03T16:11:58Z</time>
- <course>186.000000</course>
- <speed>0.000000</speed>
- </trkpt>
- <trkpt lat="51.762953300" lon="-0.005605000">
- <ele>38.710</ele>
- <time>2007-10-03T16:11:59Z</time>
- <course>186.000000</course>
- <speed>0.000000</speed>
- </trkpt>
- <trkpt lat="51.762953300" lon="-0.005605000">
- <ele>38.710</ele>
- <time>2007-10-03T16:12:02Z</time>
- <course>186.000000</course>
- <speed>0.000000</speed>
- </trkpt>
- <trkpt lat="51.762956600" lon="-0.005601600">
- <ele>38.710</ele>
- <time>2007-10-03T16:12:03Z</time>
- <course>186.000000</course>
- <speed>0.000000</speed>
- </trkpt>
- <trkpt lat="51.762956600" lon="-0.005600000">
- <ele>37.490</ele>
- <time>2007-10-03T16:12:06Z</time>
- <course>186.000000</course>
- <speed>0.000000</speed>
- </trkpt>
- <trkpt lat="51.762956600" lon="-0.005601600">
- <ele>36.576</ele>
- <time>2007-10-03T16:12:07Z</time>
- <course>186.000000</course>
- <speed>0.000000</speed>
- </trkpt>
- <trkpt lat="51.762953300" lon="-0.005606600">
- <ele>33.833</ele>
- <time>2007-10-03T16:12:10Z</time>
- <course>186.000000</course>
- <speed>0.000000</speed>
- </trkpt>
- <trkpt lat="51.762951600" lon="-0.005610000">
- <ele>33.528</ele>
- <time>2007-10-03T16:12:11Z</time>
- <course>186.000000</course>
- <speed>0.000000</speed>
- </trkpt>
- <trkpt lat="51.762965000" lon="-0.005631600">
- <ele>33.223</ele>
- <time>2007-10-03T16:12:14Z</time>
- <course>326.000000</course>
- <speed>0.000000</speed>
- </trkpt>
- <trkpt lat="51.762998300" lon="-0.005711600">
- <ele>34.138</ele>
- <time>2007-10-03T16:12:16Z</time>
- <course>309.000000</course>
- <speed>1.111111</speed>
- </trkpt>
- <trkpt lat="51.763001600" lon="-0.005720000">
- <ele>34.138</ele>
- <time>2007-10-03T16:12:18Z</time>
- <course>312.000000</course>
- <speed>0.000000</speed>
- </trkpt>
- <trkpt lat="51.763025000" lon="-0.005721600">
- <ele>33.833</ele>
- <time>2007-10-03T16:12:20Z</time>
- <course>29.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.763025000" lon="-0.005721600">
- <ele>33.833</ele>
- <time>2007-10-03T16:12:21Z</time>
- <course>29.000000</course>
- <speed>0.000000</speed>
- </trkpt>
- <trkpt lat="51.763066600" lon="-0.005625000">
- <ele>33.223</ele>
- <time>2007-10-03T16:12:24Z</time>
- <course>64.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.763074900" lon="-0.005600000">
- <ele>33.223</ele>
- <time>2007-10-03T16:12:25Z</time>
- <course>68.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.763096600" lon="-0.005538300">
- <ele>33.528</ele>
- <time>2007-10-03T16:12:28Z</time>
- <course>59.000000</course>
- <speed>1.111111</speed>
- </trkpt>
- <trkpt lat="51.763103300" lon="-0.005518300">
- <ele>33.528</ele>
- <time>2007-10-03T16:12:29Z</time>
- <course>59.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.763130000" lon="-0.005446600">
- <ele>34.442</ele>
- <time>2007-10-03T16:12:32Z</time>
- <course>61.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.763140000" lon="-0.005421600">
- <ele>34.747</ele>
- <time>2007-10-03T16:12:33Z</time>
- <course>60.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.763168300" lon="-0.005350000">
- <ele>35.662</ele>
- <time>2007-10-03T16:12:36Z</time>
- <course>64.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.763176600" lon="-0.005328300">
- <ele>35.662</ele>
- <time>2007-10-03T16:12:37Z</time>
- <course>66.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.763198300" lon="-0.005256600">
- <ele>36.881</ele>
- <time>2007-10-03T16:12:40Z</time>
- <course>69.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.763203300" lon="-0.005231600">
- <ele>37.490</ele>
- <time>2007-10-03T16:12:41Z</time>
- <course>74.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.763224900" lon="-0.005168300">
- <ele>39.014</ele>
- <time>2007-10-03T16:12:44Z</time>
- <course>66.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.763236600" lon="-0.005125000">
- <ele>39.624</ele>
- <time>2007-10-03T16:12:46Z</time>
- <course>67.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.763236600" lon="-0.005125000">
- <ele>39.624</ele>
- <time>2007-10-03T16:12:47Z</time>
- <course>67.000000</course>
- <speed>0.000000</speed>
- </trkpt>
- <trkpt lat="51.763265000" lon="-0.005040000">
- <ele>41.453</ele>
- <time>2007-10-03T16:12:50Z</time>
- <course>58.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.763273300" lon="-0.005021600">
- <ele>41.148</ele>
- <time>2007-10-03T16:12:51Z</time>
- <course>46.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.763305000" lon="-0.004971600">
- <ele>40.538</ele>
- <time>2007-10-03T16:12:54Z</time>
- <course>45.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.763314900" lon="-0.004955000">
- <ele>40.538</ele>
- <time>2007-10-03T16:12:55Z</time>
- <course>44.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.763350000" lon="-0.004909900">
- <ele>39.624</ele>
- <time>2007-10-03T16:12:58Z</time>
- <course>40.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.763359900" lon="-0.004895000">
- <ele>39.319</ele>
- <time>2007-10-03T16:12:59Z</time>
- <course>43.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.763391600" lon="-0.004846600">
- <ele>38.100</ele>
- <time>2007-10-03T16:13:02Z</time>
- <course>42.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.763403300" lon="-0.004831600">
- <ele>37.795</ele>
- <time>2007-10-03T16:13:03Z</time>
- <course>46.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.763438300" lon="-0.004793300">
- <ele>37.490</ele>
- <time>2007-10-03T16:13:06Z</time>
- <course>19.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.763453300" lon="-0.004785000">
- <ele>37.795</ele>
- <time>2007-10-03T16:13:07Z</time>
- <course>13.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.763501600" lon="-0.004773300">
- <ele>38.405</ele>
- <time>2007-10-03T16:13:10Z</time>
- <course>11.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.763518300" lon="-0.004766600">
- <ele>38.405</ele>
- <time>2007-10-03T16:13:11Z</time>
- <course>15.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.763551600" lon="-0.004726600">
- <ele>38.100</ele>
- <time>2007-10-03T16:13:14Z</time>
- <course>48.000000</course>
- <speed>1.111111</speed>
- </trkpt>
- <trkpt lat="51.763569900" lon="-0.004698300">
- <ele>38.100</ele>
- <time>2007-10-03T16:13:16Z</time>
- <course>36.000000</course>
- <speed>1.111111</speed>
- </trkpt>
- <trkpt lat="51.763590000" lon="-0.004686600">
- <ele>38.405</ele>
- <time>2007-10-03T16:13:18Z</time>
- <course>24.000000</course>
- <speed>1.111111</speed>
- </trkpt>
- <trkpt lat="51.763611600" lon="-0.004671600">
- <ele>39.014</ele>
- <time>2007-10-03T16:13:20Z</time>
- <course>20.000000</course>
- <speed>1.111111</speed>
- </trkpt>
- <trkpt lat="51.763623300" lon="-0.004665000">
- <ele>39.319</ele>
- <time>2007-10-03T16:13:21Z</time>
- <course>20.000000</course>
- <speed>1.111111</speed>
- </trkpt>
- <trkpt lat="51.763633300" lon="-0.004658300">
- <ele>39.929</ele>
- <time>2007-10-03T16:13:24Z</time>
- <course>20.000000</course>
- <speed>0.000000</speed>
- </trkpt>
- <trkpt lat="51.763659900" lon="-0.004631600">
- <ele>40.538</ele>
- <time>2007-10-03T16:13:25Z</time>
- <course>36.000000</course>
- <speed>1.111111</speed>
- </trkpt>
- <trkpt lat="51.763686600" lon="-0.004583300">
- <ele>40.538</ele>
- <time>2007-10-03T16:13:28Z</time>
- <course>44.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.763695000" lon="-0.004568300">
- <ele>40.538</ele>
- <time>2007-10-03T16:13:29Z</time>
- <course>43.000000</course>
- <speed>1.111111</speed>
- </trkpt>
- <trkpt lat="51.763723300" lon="-0.004520000">
- <ele>40.234</ele>
- <time>2007-10-03T16:13:32Z</time>
- <course>48.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.763730000" lon="-0.004503300">
- <ele>39.929</ele>
- <time>2007-10-03T16:13:33Z</time>
- <course>51.000000</course>
- <speed>1.111111</speed>
- </trkpt>
- <trkpt lat="51.763755000" lon="-0.004455000">
- <ele>39.624</ele>
- <time>2007-10-03T16:13:36Z</time>
- <course>47.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.763763300" lon="-0.004438300">
- <ele>39.624</ele>
- <time>2007-10-03T16:13:37Z</time>
- <course>48.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.763790000" lon="-0.004390000">
- <ele>39.014</ele>
- <time>2007-10-03T16:13:40Z</time>
- <course>49.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.763798300" lon="-0.004373300">
- <ele>39.014</ele>
- <time>2007-10-03T16:13:41Z</time>
- <course>48.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.763823300" lon="-0.004323300">
- <ele>38.100</ele>
- <time>2007-10-03T16:13:44Z</time>
- <course>48.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.763843300" lon="-0.004295000">
- <ele>37.795</ele>
- <time>2007-10-03T16:13:46Z</time>
- <course>45.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.763853300" lon="-0.004279900">
- <ele>37.490</ele>
- <time>2007-10-03T16:13:47Z</time>
- <course>46.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.763880000" lon="-0.004233300">
- <ele>37.186</ele>
- <time>2007-10-03T16:13:50Z</time>
- <course>52.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.763888300" lon="-0.004216600">
- <ele>37.186</ele>
- <time>2007-10-03T16:13:51Z</time>
- <course>54.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.763910000" lon="-0.004166600">
- <ele>36.576</ele>
- <time>2007-10-03T16:13:54Z</time>
- <course>54.000000</course>
- <speed>1.111111</speed>
- </trkpt>
- <trkpt lat="51.763916600" lon="-0.004146600">
- <ele>36.576</ele>
- <time>2007-10-03T16:13:55Z</time>
- <course>58.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.763941600" lon="-0.004090000">
- <ele>36.881</ele>
- <time>2007-10-03T16:13:58Z</time>
- <course>51.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.763950000" lon="-0.004071600">
- <ele>36.881</ele>
- <time>2007-10-03T16:13:59Z</time>
- <course>55.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.763973300" lon="-0.004013300">
- <ele>36.576</ele>
- <time>2007-10-03T16:14:02Z</time>
- <course>56.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.763981600" lon="-0.003995000">
- <ele>36.271</ele>
- <time>2007-10-03T16:14:03Z</time>
- <course>54.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.764006600" lon="-0.003933300">
- <ele>36.881</ele>
- <time>2007-10-03T16:14:06Z</time>
- <course>55.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.764016600" lon="-0.003915000">
- <ele>36.881</ele>
- <time>2007-10-03T16:14:07Z</time>
- <course>51.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.764041600" lon="-0.003860000">
- <ele>35.966</ele>
- <time>2007-10-03T16:14:10Z</time>
- <course>56.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.764046600" lon="-0.003843300">
- <ele>35.662</ele>
- <time>2007-10-03T16:14:11Z</time>
- <course>60.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.764068300" lon="-0.003785000">
- <ele>35.662</ele>
- <time>2007-10-03T16:14:14Z</time>
- <course>55.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.764084900" lon="-0.003748300">
- <ele>35.357</ele>
- <time>2007-10-03T16:14:16Z</time>
- <course>55.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.764101600" lon="-0.003710000">
- <ele>35.662</ele>
- <time>2007-10-03T16:14:18Z</time>
- <course>61.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.764118300" lon="-0.003666600">
- <ele>36.271</ele>
- <time>2007-10-03T16:14:20Z</time>
- <course>62.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.764126600" lon="-0.003646600">
- <ele>36.271</ele>
- <time>2007-10-03T16:14:21Z</time>
- <course>59.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.764151600" lon="-0.003583300">
- <ele>36.576</ele>
- <time>2007-10-03T16:14:24Z</time>
- <course>60.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.764159900" lon="-0.003560000">
- <ele>37.186</ele>
- <time>2007-10-03T16:14:25Z</time>
- <course>57.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.764186600" lon="-0.003493300">
- <ele>39.319</ele>
- <time>2007-10-03T16:14:28Z</time>
- <course>60.000000</course>
- <speed>1.111111</speed>
- </trkpt>
- <trkpt lat="51.764195000" lon="-0.003471600">
- <ele>39.624</ele>
- <time>2007-10-03T16:14:29Z</time>
- <course>61.000000</course>
- <speed>1.111111</speed>
- </trkpt>
- <trkpt lat="51.764218300" lon="-0.003413300">
- <ele>39.929</ele>
- <time>2007-10-03T16:14:32Z</time>
- <course>55.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.764226600" lon="-0.003395000">
- <ele>39.929</ele>
- <time>2007-10-03T16:14:33Z</time>
- <course>59.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.764248300" lon="-0.003341600">
- <ele>39.624</ele>
- <time>2007-10-03T16:14:36Z</time>
- <course>54.000000</course>
- <speed>1.111111</speed>
- </trkpt>
- <trkpt lat="51.764253300" lon="-0.003325000">
- <ele>39.319</ele>
- <time>2007-10-03T16:14:37Z</time>
- <course>56.000000</course>
- <speed>1.111111</speed>
- </trkpt>
- <trkpt lat="51.764271600" lon="-0.003268300">
- <ele>38.405</ele>
- <time>2007-10-03T16:14:40Z</time>
- <course>62.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.764278300" lon="-0.003250000">
- <ele>37.795</ele>
- <time>2007-10-03T16:14:41Z</time>
- <course>61.000000</course>
- <speed>1.111111</speed>
- </trkpt>
- <trkpt lat="51.764301600" lon="-0.003201600">
- <ele>36.576</ele>
- <time>2007-10-03T16:14:44Z</time>
- <course>35.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.764324900" lon="-0.003189900">
- <ele>35.966</ele>
- <time>2007-10-03T16:14:46Z</time>
- <course>11.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.764354900" lon="-0.003189900">
- <ele>35.966</ele>
- <time>2007-10-03T16:14:48Z</time>
- <course>346.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.764386600" lon="-0.003203300">
- <ele>36.881</ele>
- <time>2007-10-03T16:14:50Z</time>
- <course>341.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.764401600" lon="-0.003210000">
- <ele>37.490</ele>
- <time>2007-10-03T16:14:51Z</time>
- <course>334.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.764444900" lon="-0.003236600">
- <ele>38.710</ele>
- <time>2007-10-03T16:14:54Z</time>
- <course>335.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.764458300" lon="-0.003246600">
- <ele>39.014</ele>
- <time>2007-10-03T16:14:55Z</time>
- <course>335.000000</course>
- <speed>1.111111</speed>
- </trkpt>
- <trkpt lat="51.764500000" lon="-0.003268300">
- <ele>39.624</ele>
- <time>2007-10-03T16:14:58Z</time>
- <course>349.000000</course>
- <speed>1.111111</speed>
- </trkpt>
- <trkpt lat="51.764515000" lon="-0.003263300">
- <ele>39.929</ele>
- <time>2007-10-03T16:14:59Z</time>
- <course>11.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.764563300" lon="-0.003246600">
- <ele>41.453</ele>
- <time>2007-10-03T16:15:02Z</time>
- <course>2.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.764578300" lon="-0.003243300">
- <ele>42.062</ele>
- <time>2007-10-03T16:15:03Z</time>
- <course>5.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.764621600" lon="-0.003235000">
- <ele>42.672</ele>
- <time>2007-10-03T16:15:06Z</time>
- <course>1.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.764635000" lon="-0.003236600">
- <ele>42.672</ele>
- <time>2007-10-03T16:15:07Z</time>
- <course>354.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.764673300" lon="-0.003251600">
- <ele>42.977</ele>
- <time>2007-10-03T16:15:10Z</time>
- <course>348.000000</course>
- <speed>1.666667</speed>
- </trkpt>
- <trkpt lat="51.764686600" lon="-0.003255000">
- <ele>42.977</ele>
- <time>2007-10-03T16:15:11Z</time>
- <course>175.000000</course>
- <speed>1.111111</speed>
- </trkpt>
- <trkpt lat="51.764718300" lon="-0.003238300">
- <ele>43.586</ele>
- <time>2007-10-03T16:15:14Z</time>
- <course>45.000000</course>
- <speed>0.555556</speed>
- </trkpt>
- </trkseg>
- </trk>
-</gpx>
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<gpx version="1.0" creator="GPSBabel - https://www.gpsbabel.org" xmlns="http://www.topografix.com/GPX/1/0">
- <time>1970-01-01T00:00:00Z</time>
- <bounds minlat="51.759301600" minlon="-0.008520000" maxlat="51.775566600" maxlon="0.004690000"/>
- <wpt lat="51.768668300" lon="0.003845000">
- <ele>67.970</ele>
- <time>2007-09-27T13:37:38Z</time>
- <name>M000</name>
- <cmt>M000</cmt>
- <desc>M000</desc>
- <sym>Star</sym>
- </wpt>
- <wpt lat="51.768668300" lon="0.003845000">
- <ele>67.970</ele>
- <time>2007-10-03T17:04:53Z</time>
- <name>M000</name>
- <cmt>M000</cmt>
- <desc>M000</desc>
- <sym>Star</sym>
- </wpt>
- <wpt lat="51.775566600" lon="0.004690000">
- <ele>0.000</ele>
- <time>2007-09-29T14:45:02Z</time>
- <name>M001</name>
- <cmt>M001</cmt>
- <desc>M001</desc>
- <sym>Star</sym>
- </wpt>
- <wpt lat="51.775566600" lon="0.004690000">
- <ele>0.000</ele>
- <time>2007-10-03T17:04:53Z</time>
- <name>M001</name>
- <cmt>M001</cmt>
- <desc>M001</desc>
- <sym>Star</sym>
- </wpt>
- <wpt lat="51.759301600" lon="-0.008520000">
- <ele>36.271</ele>
- <time>2007-10-03T16:04:48Z</time>
- <name>M002</name>
- <cmt>M002</cmt>
- <desc>M002</desc>
- <sym>Star</sym>
- </wpt>
- <wpt lat="51.759301600" lon="-0.008520000">
- <ele>36.271</ele>
- <time>2007-10-03T17:04:53Z</time>
- <name>M002</name>
- <cmt>M002</cmt>
- <desc>M002</desc>
- <sym>Star</sym>
- </wpt>
- <wpt lat="51.759565000" lon="-0.008035000">
- <ele>35.357</ele>
- <time>2007-10-03T16:07:12Z</time>
- <name>SUBWAY</name>
- <cmt>SUBWAY</cmt>
- <desc>SUBWAY</desc>
- <sym>Star</sym>
- </wpt>
- <wpt lat="51.759565000" lon="-0.008035000">
- <ele>35.357</ele>
- <time>2007-10-03T17:04:53Z</time>
- <name>SUBWAY</name>
- <cmt>SUBWAY</cmt>
- <desc>SUBWAY</desc>
- <sym>Star</sym>
- </wpt>
-</gpx>
+++ /dev/null
-/*
- Locosys NaviGPS GT-31/BGT-31 SiRF binary logging format (SBN)
-
- Copyright (C) 2008 Rodney Lorrimar <rodney@rodney.id.au>
- Copyright (C) 2005 Robert Lipe, robertlipe+source@gpsbabel.org
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-#include <cstring> // for size_t, memcpy
-
-#include <QDate> // for QDate
-#include <QDateTime> // for QDateTime
-#include <QTime> // for QTime
-#include <QString> // for QString
-#include <QVector> // for QVector
-#include <QtGlobal> // for Q_UNUSED
-#include <Qt> // for UTC
-
-#include "defs.h"
-#include "gbfile.h" // for gbfread, gbfclose, gbfeof, gbfopen
-#include "navilink.h" // for navilink_checksum_packet, locosys_...
-
-
-#define MYNAME "sbn"
-
-static gbfile* file_handle = nullptr;
-
-static
-QVector<arglist_t> sbn_args = {
-};
-
-
-/**********************************************************************/
-
-/* Packets are encoded according to the SiRF Binary Protocol.
- *
- * http://www.navmanwirelessoem.com/oem/customer-support/oem-ne
- * ws/product-briefs-and-data-sheets/jupiter-32-xlp-new2/sirf-b
- * inary-protocol-reference-manual
- *
- * The important packet is "Geodetic Navigation Data" (Message ID 41).
- */
-
-#define PID_SBN 41
-#define SBN_RECORD_LEN 97 /* 91 plus three two shorts added by Locosys */
-/* V1.3 of the s/w added SDOP and and VSDOP bytes */
-#define PID_VISIBLE_LIST 13
-#define PID_QRY_INFORMATION 253
-#define QRY_INFORMATION_LEN 41
-#define INFO_USERNAME_LEN 13
-#define INFO_SERIAL_NUM_LEN 9
-#define INFO_LOG_RATE_LEN 3
-#define INFO_VERSION_LEN 12
-#define INFO_SEP ','
-
-
-/*
- * Very similar to read_packet in navilink.c, except reads from file
- * instead of serial, and integers are read in big endian order.
- */
-static size_t
-read_packet(int* type, void* payload, size_t max_len)
-{
- unsigned char start[4];
-
- if (gbfread(start, sizeof(start), 1, file_handle) != 1) {
- if (gbfeof(file_handle)) {
- return 0;
- }
-
- fatal(MYNAME ": Format error: No packet start.\n");
- }
-
- if (start[0] != 0xa0 || start[1] != 0xa2) {
- fatal(MYNAME ": Format error: Bad packet start.\n");
- }
-
- size_t size = be_readu16(start + 2);
-
- if (size < 1 || max_len < size) {
- fatal(MYNAME ": Format error: unexpected size: %d.\n", (int) size);
- }
-
- /* allocate space for checksum and trailing 0xb0b3 */
- size_t data_size = size + 4;
-
- /* data_size can be up to about 64k */
- auto* data = (unsigned char*) xmalloc(data_size);
-
- if (gbfread(data, data_size, 1, file_handle) != 1) {
- fatal(MYNAME ": Format error: could not read %d bytes.\n",
- (int) data_size);
- }
-
- *type = data[0];
-
- unsigned int checksum_exp = be_readu16(data + size);
- unsigned int checksum_act = navilink_checksum_packet(data, size);
-
- if (checksum_exp != checksum_act) {
- fatal(MYNAME ": Checksum error - expected %x got %x\n",
- checksum_exp, checksum_act);
- }
-
- if (data[size + 2] != 0xb0 || data[size + 3] != 0xb3) {
- fatal(MYNAME ": Format error: Bad packet trailer\n");
- }
-
- --size;
-
- memcpy(payload, data + 1, size);
- xfree(data);
-
- return size;
-}
-
-#ifdef LOCOSYS_PARSE_FILE_ID
-static size_t
-hdrcpy(char* dest, const char* src, size_t max_len)
-{
- size_t i;
-
- for (i = 0; i < max_len && *src != INFO_SEP; i++) {
- *dest++ = *src++;
- }
- *dest++ = 0;
-
- return ++i;
-}
-#endif /* LOCOSYS_PARSE_FILE_ID */
-
-bool
-locosys_decode_file_id(char* header, size_t len)
-{
- Q_UNUSED(header);
- Q_UNUSED(len);
-#ifdef LOCOSYS_PARSE_FILE_ID
- /*
- * MID_FILE_ID(0xfd) contains the following payload :
- * User Name, Serial Number, Log Rate, Firmware Version
- * >field separator:","
- * >User Name : MAX CHAR(13)
- * >Serial Number : MAX CHAR(8)
- * >Log Rate : MAX CHAR 3, 0..255 in seconds
- * >Firmware Version : MAX CHAR (13)
- */
-
- char username[INFO_USERNAME_LEN + 1];
- char serial_num[INFO_SERIAL_NUM_LEN + 1];
- char log_rate[INFO_LOG_RATE_LEN + 1];
- char version[INFO_VERSION_LEN + 1];
- char* p = header;
-
- p += hdrcpy(username, p, INFO_USERNAME_LEN);
- p += hdrcpy(serial_num, p, INFO_SERIAL_NUM_LEN);
- p += hdrcpy(log_rate, p, INFO_LOG_RATE_LEN);
- p += hdrcpy(version, p, INFO_VERSION_LEN);
-
- printf(MYNAME ": Username: %s\n", username);
- printf(MYNAME ": Serial Number: %s\n", serial_num);
- printf(MYNAME ": Log rate (seconds): %s\n", log_rate);
- printf(MYNAME ": Firmware version: %s\n", version);
-#endif /* LOCOSYS_PARSE_FILE_ID */
-
- return true;
-}
-
-static void
-read_sbn_header(route_head*)
-{
- char header[QRY_INFORMATION_LEN];
- int type = 0;
-
- size_t len = read_packet(&type, header, sizeof(header));
-
- if (len == 0 || type != PID_QRY_INFORMATION ||
- !locosys_decode_file_id(header, len)) {
- fatal(MYNAME ": Format error: Couldn't read SBN header."
- "This probably isn't a SBN file.\n");
- }
-}
-
-static int
-is_sbn_valid(const unsigned char* buffer)
-{
- /* valid navigation (any bit set implies navigation solution is not
- * optimal) */
- return !buffer[0] && !buffer[1];
-}
-
-static fix_type
-decode_sbn_mode(const unsigned char* mode)
-{
- static const fix_type fixes[8] = {
- fix_none, /* 000 No Nav */
- fix_none, /* 001 1 SV solution */
- fix_none, /* 010 2 SV solution */
- fix_2d, /* 011 3 SV solution (2D) */
- fix_3d, /* 100 4 or more SV solution (3D) */
- fix_2d, /* 101 Least Square 2D solution */
- fix_3d, /* 110 Least Square 3D solution */
- fix_none /* 111 DR solution (no SV) */
- };
- int dgps_correction = *mode & 0x80;
- fix_type fix = fixes[*mode & 7];
-
- return dgps_correction && fix == fix_3d ? fix_dgps : fix;
-}
-
-static void
-decode_sbn_datetime(const unsigned char* buffer, Waypoint* waypt)
-{
- int scaled_seconds = be_readu16(buffer + 6);
-
- int ms = scaled_seconds % 1000;
- int sec = scaled_seconds / 1000;
- int min = buffer[5];
- int hour = buffer[4];
- int mday = buffer[3];
- int mon = buffer[2];
- int year = be_readu16(buffer);
-
- waypt->SetCreationTime(QDateTime(QDate(year, mon, mday), QTime(hour, min, sec, ms), Qt::UTC));
-}
-
-static void
-decode_sbn_position(const unsigned char* buffer, Waypoint* waypt)
-{
- waypt->latitude = be_read32(buffer + 0) * 0.0000001;
- waypt->longitude = be_read32(buffer + 4) * 0.0000001;
- waypt->altitude = be_read32(buffer + 12) * 0.01;
-}
-
-static Waypoint*
-decode_sbn_record(unsigned char* buffer)
-{
- auto* waypt = new Waypoint;
-
- if (is_sbn_valid(buffer)) {
- waypt->fix = decode_sbn_mode(buffer + 3);
- } else {
- waypt->fix = fix_none;
- }
-
- decode_sbn_datetime(buffer + 10, waypt);
- decode_sbn_position(buffer + 22, waypt);
- waypt->set_speed(be_read16(buffer + 39) * 0.01f);
- waypt->set_course(be_read16(buffer + 41) * 0.01f);
- waypt->sat = buffer[87];
- waypt->hdop = buffer[88] * 0.2f;
-
- return waypt;
-}
-
-static void
-add_logpoints(route_head* track)
-{
- unsigned char buffer[SBN_RECORD_LEN];
- int type = 0;
-
- while (read_packet(&type, buffer, sizeof(buffer))) {
- if (type == PID_SBN) {
- track_add_wpt(track, decode_sbn_record(buffer));
- } else if (type == PID_VISIBLE_LIST) {
- /* A list of visible SVs, their IDs, azimuths, elevations.
- * Not storing this info for now. */
- } else {
- warning(MYNAME ": Format error: Unknown packet type 0x%02x.\n", type);
- }
- }
-}
-
-/**********************************************************************/
-
-static void
-sbn_rd_init(const QString& fname)
-{
- file_handle = gbfopen(fname, "r", MYNAME);
-}
-
-static void
-sbn_rd_deinit()
-{
- gbfclose(file_handle);
-}
-
-static void
-sbn_read()
-{
- if (global_opts.masked_objective & TRKDATAMASK) {
- auto* track = new route_head;
- track_add_head(track);
-
- read_sbn_header(track);
-
- add_logpoints(track);
- }
-}
-
-/**********************************************************************/
-
-/* Characters are always encoded in ASCII. Even if the unit is set
- * to Chinese language, only ASCII characters can be entered.
- */
-
-ff_vecs_t sbn_vecs = {
- ff_type_file,
- {
- ff_cap_none /* waypoints */,
- ff_cap_read /* tracks */,
- ff_cap_none /* routes */
- },
- sbn_rd_init,
- nullptr,
- sbn_rd_deinit,
- nullptr,
- sbn_read,
- nullptr,
- nullptr,
- &sbn_args,
- NULL_POS_OPS
-};
-/**********************************************************************/
+++ /dev/null
-/*
- Locosys NaviGPS GT-31/BGT-31 binary datalog format (SBP)
-
- Copyright (C) 2008 Rodney Lorrimar <rodney@rodney.id.au>
- Copyright (C) 2005 Robert Lipe, robertlipe+source@gpsbabel.org
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-
- */
-
-#include <cstddef> // for size_t
-
-#include <QString> // for QString
-#include <QVector> // for QVector
-
-#include "defs.h"
-#include "gbfile.h" // for gbfread, gbfclose, gbfopen, gbfile
-#include "navilink.h" // for locosys_decode_file_id, navilink_decode_logpoint
-
-
-#define MYNAME "sbp"
-
-static gbfile* file_handle = nullptr;
-
-static
-QVector<arglist_t> sbp_args = {
-};
-
-/*******************************************************************************
-* %%% global callbacks called by gpsbabel main process %%% *
-*******************************************************************************/
-
-static void
-sbp_rd_init(const QString& fname)
-{
- file_handle = gbfopen(fname, "r", MYNAME);
-}
-
-static void
-sbp_rd_deinit()
-{
- gbfclose(file_handle);
-}
-
-static void
-read_sbp_header(route_head*)
-{
- /*
- * A complete SBP file contains 64 bytes header,
- *
- * Here is the definition of the SBP header
- * BYTE 0 ~1 : true SBP header length
- * BYTE 2~63: MID_FILE_ID(0xfd)
- * will stuff 0xff for remaining bytes
- */
-
-#define HEADER_SKIP 7
-
- bool success;
- char header[64];
-
- if (gbfread(header, sizeof(header), 1, file_handle) == 1) {
- size_t len = le_read16(header) - HEADER_SKIP;
- if (len > sizeof(header)) {
- len = sizeof(header);
- }
-
- success = locosys_decode_file_id(header + HEADER_SKIP, len);
- } else {
- success = false;
- }
-
- if (!success) {
- fatal(MYNAME ": Format error: Couldn't read SBP header."
- "This probably isn't a SBP file.\n");
- }
-}
-
-static Waypoint*
-read_logpoint()
-{
- unsigned char buffer[SBP_RECORD_LEN];
-
- if (gbfread(buffer, sizeof(buffer), 1, file_handle) == 1) {
- return navilink_decode_logpoint(buffer);
- }
-
- return nullptr;
-}
-
-static void
-sbp_read()
-{
- Waypoint* logpoint;
-
- auto* track = new route_head;
- track_add_head(track);
-
- read_sbp_header(track);
-
- while ((logpoint = read_logpoint())) {
- track_add_wpt(track, logpoint);
- }
-}
-
-/**************************************************************************/
-
-/* ascii is the expected character set */
-/* not fixed, can be changed through command line parameter */
-
-ff_vecs_t sbp_vecs = {
- ff_type_file,
- {
- ff_cap_none /* waypoints */,
- ff_cap_read /* tracks */,
- ff_cap_none /* routes */
- },
- sbp_rd_init,
- nullptr,
- sbp_rd_deinit,
- nullptr,
- sbp_read,
- nullptr,
- nullptr,
- &sbp_args,
- NULL_POS_OPS
-};
-/**************************************************************************/
+++ /dev/null
-#
-# NaviLink waypoints
-#
-gpsbabel -i navilink -f ${REFERENCE}/navilink_waypoints.wpt -o gpx -F ${TMPDIR}/navilink_waypoints.gpx
-compare ${REFERENCE}/navilink_waypoints.gpx ${TMPDIR}/navilink_waypoints.gpx
-gpsbabel -i gpx -f ${TMPDIR}/navilink_waypoints.gpx -o navilink -F ${TMPDIR}/navilink_waypoints_gpx.wpt
-# not quite what we start with.
-compare ${REFERENCE}/navilink_waypoints_gpx.wpt ${TMPDIR}/navilink_waypoints_gpx.wpt
-
-#
-# NaviLink tracks
-#
-gpsbabel -t -i navilink -f ${REFERENCE}/navilink_tracks.trk -o gpx -F ${TMPDIR}/navilink_tracks.gpx
-compare ${REFERENCE}/navilink_tracks.gpx ${TMPDIR}/navilink_tracks.gpx
-gpsbabel -t -i gpx -f ${TMPDIR}/navilink_tracks.gpx -o navilink -F ${TMPDIR}/navilink_tracks_gpx.trk
-#compare ${REFERENCE}/navilink_tracks_gpx.trk ${TMPDIR}/navilink_tracks_gpx.trk
-
+++ /dev/null
-#
-# SBN tracks (Locosys NaviGPS)
-#
-gpsbabel -t -i sbn -f ${REFERENCE}/track/sbn.SBN -o gpx -F ${TMPDIR}/sbn.gpx
-compare ${REFERENCE}/track/sbn.gpx ${TMPDIR}/sbn.gpx
-
-# V1.3 of the firmware added two bytes in the packet
-gpsbabel -t -i sbn -f ${REFERENCE}/track/sbn-v13.sbn -o gpx -F ${TMPDIR}/sbn-v13.gpx
-compare ${REFERENCE}/track/sbn-v13.gpx ${TMPDIR}/sbn-v13.gpx
+++ /dev/null
-#
-# SBP tracks (Locosys NaviGPS)
-#
-gpsbabel -t -i sbp -f ${REFERENCE}/track/datalog.sbp -o gpx -F ${TMPDIR}/datalog.gpx
-compare ${REFERENCE}/track/datalog.gpx ${TMPDIR}/datalog.gpx
-
extern ff_vecs_t garmin_txt_vecs;
#endif // CSVFMTS_ENABLED
extern ff_vecs_t ggv_log_vecs;
-extern ff_vecs_t navilink_vecs;
-extern ff_vecs_t sbp_vecs;
-extern ff_vecs_t sbn_vecs;
extern ff_vecs_t v900_vecs;
extern ff_vecs_t format_garmin_xt_vecs;
#endif // MAXIMAL_ENABLED
Dg100FileFormat dg100_ffmt;
Dg200SerialFormat dg200_fmt;
Dg200FileFormat dg200_ffmt;
- LegacyFormat navilink_fmt {navilink_vecs};
OsmFormat osm_fmt;
ExifFormat exif_fmt;
HumminbirdFormat humminbird_fmt;
HumminbirdHTFormat humminbird_ht_fmt;
- LegacyFormat sbp_fmt {sbp_vecs};
- LegacyFormat sbn_fmt {sbn_vecs};
LegacyFormat v900_fmt {v900_vecs};
SkytraqFormat skytraq_fmt;
SkytraqfileFormat skytraq_ffmt;
nullptr,
nullptr,
},
- {
- &navilink_fmt,
- "navilink",
- "NaviGPS GT-11/BGT-11 Download",
- nullptr,
- nullptr,
- },
{
&osm_fmt,
"osm",
"ht",
nullptr,
},
- {
- &sbp_fmt,
- "sbp",
- "NaviGPS GT-31/BGT-31 datalogger (.sbp)",
- "sbp",
- nullptr,
- },
- {
- &sbn_fmt,
- "sbn",
- "NaviGPS GT-31/BGT-31 SiRF binary logfile (.sbn)",
- "sbn",
- nullptr,
- },
{
&v900_fmt,
"v900",
+++ /dev/null
-<para>
- GPSBabel supports the Navilink protocol used by the
- <link xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="http://www.locosystech.com/product.php?zln=en&id=5">Locosys GT-11</link>
- and
- <link xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="http://www.locosystech.com/product.php?zln=en&id=30">GT-31</link>
- GPS receivers. These are sold under a variety of names including:
-<simplelist columns="3" type="vert">
- <member>NaviGPS</member>
- <member>NaviGPS-BT</member>
- <member>GT-11</member>
- <member>BGT-11</member>
- <member>GT-31</member>
- <member>BGT-31</member>
- <member>Amaryllo</member>
-</simplelist>
-</para>
-<para>
- This format is used for both the serial protocol used on
- the USB link and for the files which can be copied from the
- internal memory to the SD card using recent firmware versions.
-</para>
-<para>
- If you specify a serial port for the file (.e.g. "COM1", "/dev/ttyUSB0")
- to be read or written, GPSBabel will use the serial protocol. Specifying
- a file, either on local filesystem or on a mounted flash card reader,
- will results in the file-based format being used.
-</para>
-<para>
- To access the device using the serial protocol over USB the
- device needs to be in Navilink mode, which can be activated
- from the main menu of the device. This device uses a Prolific
- PL2303 USB/Serial adapter internally and that's how it will
- present itself to the host operating system. You thus need
- USB drivers for the PL2303, such as those from the 'Download'
- section of
- <link xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="http://www.locosystech.com/product.php?zln=en&id=30#">
- Locosys USB Genie GT-31/BGT-31 drivers
- </link>.
-</para>
-<para>
- Details of the Navilink serial protocol can be found
- <link xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="http://notes.splitbrain.org/navilink">here</link>.
-</para>
+++ /dev/null
-<para>
- This format is for SBN datalog files saved to the SD card by
- the Locosys GT-11/BGT-11/GT-31/BGT-31 GPS receivers.
-</para>
-<para>
- On the device, logging in this format is enabled by choosing
- SBN from the NMEA ITEMS menu on the MEMORY CARD screen.
-</para>
-<para>
- Not all data logged in this format is converted by GPSBabel,
- but the following are:
-
-<simplelist columns="3" type="vert">
- <member>Position</member>
- <member>Elevation</member>
- <member>Time</member>
- <member>Fix type (2D/3D/DGPS)</member>
- <member>Speed</member>
- <member>Course</member>
- <member>Number of satellites visible</member>
- <member>Horizontal Dilution of Precision (HDOP)</member>
-</simplelist>
-</para>
-
-<para>
- The specification of this format can be found in
- the <link xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="http://www.navmanwirelessoem.com/oem/customer-support/oem-news/product-briefs-and-data-sheets/jupiter-32-xlp-new2/sirf-binary-protocol-reference-manual">
- SiRF Binary Protocol Reference Manual</link>, in the section
- called Geodetic Navigation Data - Message ID 41.
-</para>
+++ /dev/null
-<para>
- This format is for SBP datalog files saved to the SD card by
- the Locosys GT-11/BGT-11/GT-31/BGT-31 GPS receivers.
-</para>